@@ -6,16 +6,14 @@ use axum::{Router, routing::get};
66use axum:: { extract:: State , response:: IntoResponse } ;
77use clap:: { Parser , Subcommand } ;
88use firebase_auth:: FirebaseAuth ;
9- use http:: StatusCode ;
109use sqlx:: postgres:: PgPoolOptions ;
11- use sqlx:: { PgPool , Postgres } ;
1210use sqlx_migrator:: cli:: MigrationCommand ;
1311use sqlx_migrator:: migrator:: { Migrate , Migrator } ;
1412use sqlx_migrator:: { Info , Plan } ;
1513use std:: collections:: HashSet ;
1614use std:: path:: Path ;
1715use std:: sync:: Arc ;
18- use tokio:: sync:: { RwLock , watch } ;
16+ use tokio:: sync:: RwLock ;
1917use tower:: ServiceBuilder ;
2018use tower_http:: cors:: CorsLayer ;
2119use tracing:: { error, info} ;
@@ -26,10 +24,9 @@ mod auth;
2624mod automerge_json;
2725mod document;
2826mod rpc;
27+ mod storage;
2928mod user;
3029
31- use app:: AppStatus ;
32-
3330/// Port for the web server providing the RPC API.
3431fn web_port ( ) -> String {
3532 dotenvy:: var ( "PORT" ) . unwrap_or ( "8000" . to_string ( ) )
@@ -100,17 +97,21 @@ async fn main() {
10097 }
10198
10299 Command :: Serve => {
103- let ( status_tx, status_rx) = watch:: channel ( AppStatus :: Starting ) ;
100+ info ! ( "Applying database migrations..." ) ;
101+ let mut conn = db. acquire ( ) . await . expect ( "Failed to acquire DB connection" ) ;
102+ migrator
103+ . run ( & mut conn, & Plan :: apply_all ( ) )
104+ . await
105+ . expect ( "Failed to run migrations" ) ;
106+ info ! ( "Migrations complete" ) ;
104107
105- // Create samod repo
106108 let repo = samod:: Repo :: builder ( tokio:: runtime:: Handle :: current ( ) )
107- . with_storage ( samod :: storage:: InMemoryStorage :: new ( ) )
109+ . with_storage ( storage:: PostgresStorage :: new ( db . clone ( ) ) )
108110 . load ( )
109111 . await ;
110112
111113 let state = app:: AppState {
112114 db : db. clone ( ) ,
113- app_status : status_rx. clone ( ) ,
114115 repo,
115116 active_listeners : Arc :: new ( RwLock :: new ( HashSet :: new ( ) ) ) ,
116117 } ;
@@ -127,48 +128,10 @@ async fn main() {
127128 . await ,
128129 ) ;
129130
130- tokio:: try_join!(
131- run_migrator_apply( db. clone( ) , migrator, status_tx. clone( ) ) ,
132- run_web_server( state. clone( ) , firebase_auth. clone( ) ) ,
133- )
134- . unwrap ( ) ;
135- }
136- }
137- }
138-
139- async fn run_migrator_apply (
140- db : PgPool ,
141- migrator : Migrator < Postgres > ,
142- status_tx : watch:: Sender < AppStatus > ,
143- ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
144- status_tx. send ( AppStatus :: Migrating ) ?;
145- info ! ( "Applying database migrations..." ) ;
146-
147- let mut conn = db. acquire ( ) . await ?;
148- migrator. run ( & mut conn, & Plan :: apply_all ( ) ) . await . unwrap ( ) ;
131+ // Notify systemd we're ready
132+ sd_notify:: notify ( false , & [ sd_notify:: NotifyState :: Ready ] ) . ok ( ) ;
149133
150- status_tx. send ( AppStatus :: Running ) ?;
151- sd_notify:: notify ( false , & [ sd_notify:: NotifyState :: Ready ] ) ?;
152- info ! ( "Migrations complete" ) ;
153-
154- Ok ( ( ) )
155- }
156-
157- async fn app_status_gate (
158- State ( status_rx) : State < watch:: Receiver < AppStatus > > ,
159- req : Request ,
160- next : Next ,
161- ) -> impl IntoResponse {
162- // Combining the following 2 lines will anger the rust gods
163- let status = status_rx. borrow ( ) . clone ( ) ;
164- match status {
165- AppStatus :: Running => next. run ( req) . await ,
166- AppStatus :: Failed ( reason) => {
167- ( StatusCode :: INTERNAL_SERVER_ERROR , format ! ( "App failed to start: {reason}" ) )
168- . into_response ( )
169- }
170- AppStatus :: Starting | AppStatus :: Migrating => {
171- ( StatusCode :: SERVICE_UNAVAILABLE , "Server not ready yet" ) . into_response ( )
134+ run_web_server ( state. clone ( ) , firebase_auth. clone ( ) ) . await . unwrap ( ) ;
172135 }
173136 }
174137}
@@ -191,13 +154,8 @@ async fn auth_middleware(
191154 next. run ( req) . await
192155}
193156
194- async fn status_handler ( State ( status_rx) : State < watch:: Receiver < AppStatus > > ) -> String {
195- match status_rx. borrow ( ) . clone ( ) {
196- AppStatus :: Starting => "Starting" . into ( ) ,
197- AppStatus :: Migrating => "Migrating" . into ( ) ,
198- AppStatus :: Running => "Running" . into ( ) ,
199- AppStatus :: Failed ( reason) => format ! ( "Failed: {reason}" ) ,
200- }
157+ async fn status_handler ( ) -> & ' static str {
158+ "Running"
201159}
202160
203161async fn websocket_handler (
@@ -223,20 +181,16 @@ async fn run_web_server(
223181 let ( qubit_service, qubit_handle) = rpc_router. as_rpc ( state. clone ( ) ) . into_service ( ) ;
224182
225183 let rpc_with_mw = ServiceBuilder :: new ( )
226- . layer ( from_fn_with_state ( state. app_status . clone ( ) , app_status_gate) )
227184 . layer ( from_fn_with_state ( firebase_auth. clone ( ) , auth_middleware) )
228185 . service ( qubit_service) ;
229186
230187 let samod_router = Router :: new ( )
231188 . layer ( from_fn_with_state ( firebase_auth, auth_middleware) )
232- . layer ( from_fn_with_state ( state. app_status . clone ( ) , app_status_gate) )
233189 . route ( "/repo-ws" , get ( websocket_handler) )
234190 . with_state ( state. repo . clone ( ) ) ;
235191
236192 // used by tests to tell when the backend is ready
237- let status_router = Router :: new ( )
238- . route ( "/status" , get ( status_handler) )
239- . with_state ( state. app_status . clone ( ) ) ;
193+ let status_router = Router :: new ( ) . route ( "/status" , get ( status_handler) ) ;
240194
241195 let mut app = Router :: new ( )
242196 . merge ( status_router)
0 commit comments