2023-07-29 21:57:41 +00:00
use std ::{
fs ::Permissions , future ::Future , io , net ::SocketAddr , os ::unix ::fs ::PermissionsExt ,
sync ::atomic , time ::Duration ,
} ;
2021-06-08 18:10:00 +02:00
2022-01-20 11:51:31 +01:00
use axum ::{
2023-06-29 11:20:52 +02:00
extract ::{ DefaultBodyLimit , FromRequestParts , MatchedPath } ,
2022-01-22 13:51:55 +01:00
response ::IntoResponse ,
2022-01-20 11:51:31 +01:00
routing ::{ get , on , MethodFilter } ,
2023-11-27 00:39:50 -05:00
Router ,
2022-01-20 11:51:31 +01:00
} ;
2022-01-22 18:38:39 +01:00
use axum_server ::{ bind , bind_rustls , tls_rustls ::RustlsConfig , Handle as ServerHandle } ;
2022-10-08 13:02:52 +02:00
use conduit ::api ::{ client_server , server_server } ;
2022-01-20 11:51:31 +01:00
use figment ::{
providers ::{ Env , Format , Toml } ,
Figment ,
} ;
use http ::{
header ::{ self , HeaderName } ,
2022-10-15 16:56:08 +02:00
Method , StatusCode , Uri ,
2022-01-20 11:51:31 +01:00
} ;
2023-07-29 21:57:41 +00:00
use hyper ::Server ;
use hyperlocal ::SocketIncoming ;
2022-10-15 16:56:08 +02:00
use ruma ::api ::{
2022-10-31 09:31:17 +01:00
client ::{
2022-12-17 09:21:19 +01:00
error ::{ Error as RumaError , ErrorBody , ErrorKind } ,
2022-10-31 09:31:17 +01:00
uiaa ::UiaaResponse ,
} ,
2022-10-15 16:56:08 +02:00
IncomingRequest ,
} ;
2023-07-29 21:57:41 +00:00
use tokio ::{ net ::UnixListener , signal , sync ::oneshot } ;
2022-01-20 11:51:31 +01:00
use tower ::ServiceBuilder ;
use tower_http ::{
cors ::{ self , CorsLayer } ,
trace ::TraceLayer ,
ServiceBuilderExt as _ ,
2020-12-31 21:07:05 +01:00
} ;
2023-08-03 14:51:39 -10:00
use tracing ::{ debug , error , info , warn } ;
2021-07-29 08:36:01 +02:00
use tracing_subscriber ::{ prelude ::* , EnvFilter } ;
2020-04-03 17:27:08 +02:00
2023-07-29 21:57:41 +00:00
use tokio ::sync ::oneshot ::Sender ;
2023-11-25 15:53:33 -05:00
use clap ::Parser ;
2022-01-18 21:04:44 +01:00
pub use conduit ::* ; // Re-export everything from the library crate
2022-02-04 16:59:30 +01:00
#[ cfg(all(not(target_env = " msvc " ), feature = " jemalloc " )) ]
2022-01-21 09:19:19 +01:00
use tikv_jemallocator ::Jemalloc ;
2022-02-04 16:59:30 +01:00
#[ cfg(all(not(target_env = " msvc " ), feature = " jemalloc " )) ]
2022-01-21 09:19:19 +01:00
#[ global_allocator ]
static GLOBAL : Jemalloc = Jemalloc ;
2023-11-25 15:53:33 -05:00
#[ derive(Parser) ]
#[ clap(version, about, long_about = None) ]
struct Args { }
2022-09-06 23:15:09 +02:00
#[ tokio::main ]
async fn main ( ) {
2023-11-25 15:53:33 -05:00
Args ::parse ( ) ;
2023-08-03 14:51:39 -10:00
// Initialize config
2022-09-06 23:15:09 +02:00
let raw_config =
Figment ::new ( )
. merge (
Toml ::file ( Env ::var ( " CONDUIT_CONFIG " ) . expect (
" The CONDUIT_CONFIG env var needs to be set. Example: /etc/conduit.toml " ,
) )
. nested ( ) ,
)
. merge ( Env ::prefixed ( " CONDUIT_ " ) . global ( ) ) ;
2022-06-25 16:12:23 +02:00
2022-09-06 23:15:09 +02:00
let config = match raw_config . extract ::< Config > ( ) {
Ok ( s ) = > s ,
Err ( e ) = > {
2022-12-21 10:42:12 +01:00
eprintln! ( " It looks like your config is invalid. The following error occurred: {e} " ) ;
2023-07-29 21:57:41 +00:00
return ;
2022-09-06 23:15:09 +02:00
}
} ;
2021-04-24 13:34:35 +02:00
2021-02-28 12:41:03 +01:00
if config . allow_jaeger {
2021-08-19 11:01:18 +02:00
opentelemetry ::global ::set_text_map_propagator ( opentelemetry_jaeger ::Propagator ::new ( ) ) ;
2022-10-09 15:34:36 +02:00
let tracer = opentelemetry_jaeger ::new_agent_pipeline ( )
2022-12-18 06:37:03 +01:00
. with_auto_split_batch ( true )
. with_service_name ( " conduit " )
2023-12-21 20:32:53 -08:00
. install_batch ( opentelemetry_sdk ::runtime ::Tokio )
2021-02-28 12:41:03 +01:00
. unwrap ( ) ;
2022-12-18 06:37:03 +01:00
let telemetry = tracing_opentelemetry ::layer ( ) . with_tracer ( tracer ) ;
2021-02-28 12:41:03 +01:00
2023-10-28 22:14:21 -04:00
let filter_layer = match EnvFilter ::try_new ( & config . log ) {
2022-12-18 06:37:03 +01:00
Ok ( s ) = > s ,
Err ( e ) = > {
eprintln! (
2022-12-21 10:42:12 +01:00
" It looks like your log config is invalid. The following error occurred: {e} "
2022-12-18 06:37:03 +01:00
) ;
EnvFilter ::try_new ( " warn " ) . unwrap ( )
}
} ;
2021-08-19 11:01:18 +02:00
2022-12-18 06:37:03 +01:00
let subscriber = tracing_subscriber ::Registry ::default ( )
. with ( filter_layer )
. with ( telemetry ) ;
tracing ::subscriber ::set_global_default ( subscriber ) . unwrap ( ) ;
2022-12-18 07:47:18 +01:00
} else if config . tracing_flame {
let registry = tracing_subscriber ::Registry ::default ( ) ;
let ( flame_layer , _guard ) =
tracing_flame ::FlameLayer ::with_file ( " ./tracing.folded " ) . unwrap ( ) ;
let flame_layer = flame_layer . with_empty_samples ( false ) ;
let filter_layer = EnvFilter ::new ( " trace,h2=off " ) ;
let subscriber = registry . with ( filter_layer ) . with ( flame_layer ) ;
tracing ::subscriber ::set_global_default ( subscriber ) . unwrap ( ) ;
2021-02-28 12:41:03 +01:00
} else {
2021-07-29 08:36:01 +02:00
let registry = tracing_subscriber ::Registry ::default ( ) ;
2022-12-18 07:47:18 +01:00
let fmt_layer = tracing_subscriber ::fmt ::Layer ::new ( ) ;
2023-10-28 22:14:21 -04:00
let filter_layer = match EnvFilter ::try_new ( & config . log ) {
2022-12-18 07:47:18 +01:00
Ok ( s ) = > s ,
Err ( e ) = > {
2022-12-21 10:42:12 +01:00
eprintln! ( " It looks like your config is invalid. The following error occured while parsing it: {e} " ) ;
2022-12-18 07:47:18 +01:00
EnvFilter ::try_new ( " warn " ) . unwrap ( )
}
} ;
let subscriber = registry . with ( filter_layer ) . with ( fmt_layer ) ;
tracing ::subscriber ::set_global_default ( subscriber ) . unwrap ( ) ;
}
2023-08-03 14:51:39 -10:00
// This is needed for opening lots of file descriptors, which tends to
// happen more often when using RocksDB and making lots of federation
// connections at startup. The soft limit is usually 1024, and the hard
// limit is usually 512000; I've personally seen it hit >2000.
//
// * https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.12.2.1.17.6
// * https://github.com/systemd/systemd/commit/0abf94923b4a95a7d89bc526efc84e7ca2b71741
#[ cfg(unix) ]
2024-01-07 21:23:42 -05:00
maximize_fd_limit ( ) . expect ( " Unable to increase maximum soft and hard file descriptor limit " ) ;
2023-08-03 14:51:39 -10:00
2023-07-29 21:57:41 +00:00
config . warn_deprecated ( ) ;
2023-11-29 21:36:02 -05:00
if config . is_dual_listening ( raw_config ) {
2023-07-29 21:57:41 +00:00
return ;
} ;
2022-12-18 07:47:18 +01:00
info! ( " Loading database " ) ;
if let Err ( error ) = KeyValueDatabase ::load_or_create ( config ) . await {
error! ( ? error , " The database couldn't be loaded or created " ) ;
2023-07-29 21:57:41 +00:00
return ;
2022-12-18 07:47:18 +01:00
} ;
let config = & services ( ) . globals . config ;
2023-12-24 00:36:14 -05:00
if config . allow_registration
& & ! config . yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
{
2023-12-25 15:11:08 -05:00
error! ( " !! You have `allow_registration` enabled in your config which means you are allowing ANYONE to register on your conduwuit instance without any 2nd-step (e.g. registration token). \n
2023-12-24 00:36:14 -05:00
If this is not the intended behaviour , please disable ` allow_registration ` and set a registration token . \ n
For security and safety reasons , conduwuit will shut down . If you are extra sure this is the desired behaviour you want , please set the following config option to true :
` yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse ` " );
return ;
}
if config . allow_registration
& & config . yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
{
2023-12-25 15:11:08 -05:00
warn! ( " Open registration is enabled via setting `yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse` and `allow_registration` to true. You are expected to be aware of the risks now. \n
2023-12-24 00:36:14 -05:00
If this is not the desired behaviour , please disable ` allow_registration ` and set a registration token . " );
}
2022-12-18 07:47:18 +01:00
info! ( " Starting server " ) ;
2023-12-24 01:12:52 -05:00
if let Err ( e ) = run_server ( ) . await {
error! ( " Critical error running server: {} " , e ) ;
} ;
2022-12-18 07:47:18 +01:00
2023-12-24 00:38:06 -05:00
// if server runs into critical error and shuts down, shut down the tracer provider if jaegar is used.
// awaiting run_server() is a blocking call so putting this after is fine, but not the other options above.
2022-12-18 07:47:18 +01:00
if config . allow_jaeger {
opentelemetry ::global ::shutdown_tracer_provider ( ) ;
2021-07-29 08:36:01 +02:00
}
2020-02-15 22:42:21 +01:00
}
2020-12-19 16:00:11 +01:00
2022-06-25 16:12:23 +02:00
async fn run_server ( ) -> io ::Result < ( ) > {
2022-10-08 13:02:52 +02:00
let config = & services ( ) . globals . config ;
2022-01-22 18:38:39 +01:00
let addr = SocketAddr ::from ( ( config . address , config . port ) ) ;
2021-02-06 15:27:43 +01:00
2022-01-20 11:51:31 +01:00
let x_requested_with = HeaderName ::from_static ( " x-requested-with " ) ;
2021-02-06 15:27:43 +01:00
2022-01-20 11:51:31 +01:00
let middlewares = ServiceBuilder ::new ( )
. sensitive_headers ( [ header ::AUTHORIZATION ] )
2023-03-17 22:44:50 +01:00
. layer ( axum ::middleware ::from_fn ( spawn_task ) )
2022-01-20 11:51:31 +01:00
. layer (
TraceLayer ::new_for_http ( ) . make_span_with ( | request : & http ::Request < _ > | {
let path = if let Some ( path ) = request . extensions ( ) . get ::< MatchedPath > ( ) {
path . as_str ( )
} else {
request . uri ( ) . path ( )
} ;
tracing ::info_span! ( " http_request " , % path )
} ) ,
)
2022-10-15 00:28:43 +02:00
. layer ( axum ::middleware ::from_fn ( unrecognized_method ) )
2022-01-20 11:51:31 +01:00
. layer (
CorsLayer ::new ( )
2022-04-07 17:09:07 +02:00
. allow_origin ( cors ::Any )
2022-01-20 11:51:31 +01:00
. allow_methods ( [
Method ::GET ,
2024-01-09 21:02:57 -05:00
Method ::HEAD ,
2022-01-20 11:51:31 +01:00
Method ::POST ,
Method ::PUT ,
Method ::DELETE ,
Method ::OPTIONS ,
] )
. allow_headers ( [
header ::ORIGIN ,
x_requested_with ,
header ::CONTENT_TYPE ,
header ::ACCEPT ,
header ::AUTHORIZATION ,
] )
. max_age ( Duration ::from_secs ( 86400 ) ) ,
2022-10-25 12:53:58 +03:00
)
. layer ( DefaultBodyLimit ::max (
config
. max_request_size
. try_into ( )
. expect ( " failed to convert max request size " ) ,
) ) ;
2022-01-20 11:51:31 +01:00
2023-11-27 00:39:50 -05:00
let app = if cfg! ( feature = " zstd_compression " ) & & config . zstd_compression {
2023-11-25 01:30:19 -05:00
debug! ( " zstd body compression is enabled " ) ;
2023-11-27 00:39:50 -05:00
routes ( )
2023-11-25 01:30:19 -05:00
. layer ( middlewares . compression ( ) )
2023-11-27 00:39:50 -05:00
. into_make_service ( )
2023-11-25 01:30:19 -05:00
} else {
2023-11-27 00:39:50 -05:00
routes ( ) . layer ( middlewares ) . into_make_service ( )
} ;
2022-01-22 18:38:39 +01:00
let handle = ServerHandle ::new ( ) ;
2023-07-29 21:57:41 +00:00
let ( tx , rx ) = oneshot ::channel ::< ( ) > ( ) ;
2022-01-22 18:38:39 +01:00
2023-07-29 21:57:41 +00:00
tokio ::spawn ( shutdown_signal ( handle . clone ( ) , tx ) ) ;
2022-01-22 18:38:39 +01:00
2023-07-29 21:57:41 +00:00
if let Some ( path ) = & config . unix_socket_path {
if path . exists ( ) {
warn! (
" UNIX socket path {:#?} already exists (unclean shutdown?), attempting to remove it. " ,
path . display ( )
) ;
tokio ::fs ::remove_file ( & path ) . await ? ;
}
2022-11-25 21:23:21 +01:00
2023-07-29 21:57:41 +00:00
tokio ::fs ::create_dir_all ( path . parent ( ) . unwrap ( ) ) . await ? ;
2022-11-25 21:23:21 +01:00
2023-07-29 21:57:41 +00:00
let socket_perms = config . unix_socket_perms . to_string ( ) ;
let octal_perms = u32 ::from_str_radix ( & socket_perms , 8 ) . unwrap ( ) ;
2022-11-25 21:23:21 +01:00
2023-07-29 21:57:41 +00:00
let listener = UnixListener ::bind ( path . clone ( ) ) . unwrap ( ) ;
tokio ::fs ::set_permissions ( path , Permissions ::from_mode ( octal_perms ) )
. await
. unwrap ( ) ;
let socket = SocketIncoming ::from_listener ( listener ) ;
#[ cfg(feature = " systemd " ) ]
let _ = sd_notify ::notify ( true , & [ sd_notify ::NotifyState ::Ready ] ) ;
2023-12-25 15:11:38 -05:00
info! ( " Listening at {:?} " , path ) ;
2023-07-29 21:57:41 +00:00
let server = Server ::builder ( socket ) . serve ( app ) ;
let graceful = server . with_graceful_shutdown ( async {
rx . await . ok ( ) ;
} ) ;
if let Err ( e ) = graceful . await {
error! ( " Server error: {:?} " , e ) ;
}
} else {
match & config . tls {
Some ( tls ) = > {
let conf = RustlsConfig ::from_pem_file ( & tls . certs , & tls . key ) . await ? ;
let server = bind_rustls ( addr , conf ) . handle ( handle ) . serve ( app ) ;
#[ cfg(feature = " systemd " ) ]
let _ = sd_notify ::notify ( true , & [ sd_notify ::NotifyState ::Ready ] ) ;
2023-12-25 15:11:38 -05:00
info! ( " Listening on {} " , addr ) ;
2023-07-29 21:57:41 +00:00
server . await ?
}
None = > {
let server = bind ( addr ) . handle ( handle ) . serve ( app ) ;
2022-11-25 21:23:21 +01:00
2023-07-29 21:57:41 +00:00
#[ cfg(feature = " systemd " ) ]
let _ = sd_notify ::notify ( true , & [ sd_notify ::NotifyState ::Ready ] ) ;
2023-12-25 15:11:38 -05:00
info! ( " Listening on {} " , addr ) ;
2023-07-29 21:57:41 +00:00
server . await ?
}
2022-01-22 18:38:39 +01:00
}
}
2022-01-20 11:51:31 +01:00
Ok ( ( ) )
2021-02-06 15:27:43 +01:00
}
2023-03-17 22:44:50 +01:00
async fn spawn_task < B : Send + 'static > (
req : axum ::http ::Request < B > ,
next : axum ::middleware ::Next < B > ,
) -> std ::result ::Result < axum ::response ::Response , StatusCode > {
2023-03-18 08:58:20 +01:00
if services ( ) . globals . shutdown . load ( atomic ::Ordering ::Relaxed ) {
return Err ( StatusCode ::SERVICE_UNAVAILABLE ) ;
}
2023-03-17 22:44:50 +01:00
tokio ::spawn ( next . run ( req ) )
. await
. map_err ( | _ | StatusCode ::INTERNAL_SERVER_ERROR )
}
2023-11-27 21:34:45 -05:00
async fn unrecognized_method < B : Send + 'static > (
2022-10-15 00:28:43 +02:00
req : axum ::http ::Request < B > ,
next : axum ::middleware ::Next < B > ,
2022-10-15 16:56:08 +02:00
) -> std ::result ::Result < axum ::response ::Response , StatusCode > {
2022-10-15 00:28:43 +02:00
let method = req . method ( ) . clone ( ) ;
let uri = req . uri ( ) . clone ( ) ;
let inner = next . run ( req ) . await ;
if inner . status ( ) = = axum ::http ::StatusCode ::METHOD_NOT_ALLOWED {
warn! ( " Method not allowed: {method} {uri} " ) ;
2022-10-15 16:56:08 +02:00
return Ok ( RumaResponse ( UiaaResponse ::MatrixError ( RumaError {
2022-12-17 09:21:19 +01:00
body : ErrorBody ::Standard {
kind : ErrorKind ::Unrecognized ,
message : " M_UNRECOGNIZED: Unrecognized request " . to_owned ( ) ,
} ,
2022-10-15 16:56:08 +02:00
status_code : StatusCode ::METHOD_NOT_ALLOWED ,
} ) )
. into_response ( ) ) ;
2022-10-15 00:28:43 +02:00
}
Ok ( inner )
}
2022-01-20 11:51:31 +01:00
fn routes ( ) -> Router {
Router ::new ( )
. ruma_route ( client_server ::get_supported_versions_route )
. ruma_route ( client_server ::get_register_available_route )
. ruma_route ( client_server ::register_route )
. ruma_route ( client_server ::get_login_types_route )
. ruma_route ( client_server ::login_route )
. ruma_route ( client_server ::whoami_route )
. ruma_route ( client_server ::logout_route )
. ruma_route ( client_server ::logout_all_route )
. ruma_route ( client_server ::change_password_route )
. ruma_route ( client_server ::deactivate_route )
. ruma_route ( client_server ::third_party_route )
2022-10-25 20:47:41 +00:00
. ruma_route ( client_server ::request_3pid_management_token_via_email_route )
. ruma_route ( client_server ::request_3pid_management_token_via_msisdn_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( client_server ::get_capabilities_route )
. ruma_route ( client_server ::get_pushrules_all_route )
. ruma_route ( client_server ::set_pushrule_route )
. ruma_route ( client_server ::get_pushrule_route )
. ruma_route ( client_server ::set_pushrule_enabled_route )
. ruma_route ( client_server ::get_pushrule_enabled_route )
. ruma_route ( client_server ::get_pushrule_actions_route )
. ruma_route ( client_server ::set_pushrule_actions_route )
. ruma_route ( client_server ::delete_pushrule_route )
. ruma_route ( client_server ::get_room_event_route )
. ruma_route ( client_server ::get_room_aliases_route )
. ruma_route ( client_server ::get_filter_route )
. ruma_route ( client_server ::create_filter_route )
. ruma_route ( client_server ::set_global_account_data_route )
. ruma_route ( client_server ::set_room_account_data_route )
. ruma_route ( client_server ::get_global_account_data_route )
. ruma_route ( client_server ::get_room_account_data_route )
. ruma_route ( client_server ::set_displayname_route )
. ruma_route ( client_server ::get_displayname_route )
. ruma_route ( client_server ::set_avatar_url_route )
. ruma_route ( client_server ::get_avatar_url_route )
. ruma_route ( client_server ::get_profile_route )
. ruma_route ( client_server ::set_presence_route )
. ruma_route ( client_server ::get_presence_route )
. ruma_route ( client_server ::upload_keys_route )
. ruma_route ( client_server ::get_keys_route )
. ruma_route ( client_server ::claim_keys_route )
2022-04-06 19:01:16 +02:00
. ruma_route ( client_server ::create_backup_version_route )
. ruma_route ( client_server ::update_backup_version_route )
. ruma_route ( client_server ::delete_backup_version_route )
. ruma_route ( client_server ::get_latest_backup_info_route )
. ruma_route ( client_server ::get_backup_info_route )
2022-04-10 14:56:43 +02:00
. ruma_route ( client_server ::add_backup_keys_route )
2022-04-06 19:01:16 +02:00
. ruma_route ( client_server ::add_backup_keys_for_room_route )
. ruma_route ( client_server ::add_backup_keys_for_session_route )
. ruma_route ( client_server ::delete_backup_keys_for_room_route )
. ruma_route ( client_server ::delete_backup_keys_for_session_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( client_server ::delete_backup_keys_route )
2022-04-06 19:01:16 +02:00
. ruma_route ( client_server ::get_backup_keys_for_room_route )
. ruma_route ( client_server ::get_backup_keys_for_session_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( client_server ::get_backup_keys_route )
. ruma_route ( client_server ::set_read_marker_route )
. ruma_route ( client_server ::create_receipt_route )
. ruma_route ( client_server ::create_typing_event_route )
. ruma_route ( client_server ::create_room_route )
. ruma_route ( client_server ::redact_event_route )
. ruma_route ( client_server ::report_event_route )
. ruma_route ( client_server ::create_alias_route )
. ruma_route ( client_server ::delete_alias_route )
. ruma_route ( client_server ::get_alias_route )
. ruma_route ( client_server ::join_room_by_id_route )
. ruma_route ( client_server ::join_room_by_id_or_alias_route )
. ruma_route ( client_server ::joined_members_route )
. ruma_route ( client_server ::leave_room_route )
. ruma_route ( client_server ::forget_room_route )
. ruma_route ( client_server ::joined_rooms_route )
. ruma_route ( client_server ::kick_user_route )
. ruma_route ( client_server ::ban_user_route )
. ruma_route ( client_server ::unban_user_route )
. ruma_route ( client_server ::invite_user_route )
. ruma_route ( client_server ::set_room_visibility_route )
. ruma_route ( client_server ::get_room_visibility_route )
. ruma_route ( client_server ::get_public_rooms_route )
. ruma_route ( client_server ::get_public_rooms_filtered_route )
. ruma_route ( client_server ::search_users_route )
. ruma_route ( client_server ::get_member_events_route )
. ruma_route ( client_server ::get_protocols_route )
. ruma_route ( client_server ::send_message_event_route )
. ruma_route ( client_server ::send_state_event_for_key_route )
. ruma_route ( client_server ::get_state_events_route )
. ruma_route ( client_server ::get_state_events_for_key_route )
2022-01-22 14:45:12 +01:00
// Ruma doesn't have support for multiple paths for a single endpoint yet, and these routes
// share one Ruma request / response type pair with {get,send}_state_event_for_key_route
. route (
" /_matrix/client/r0/rooms/:room_id/state/:event_type " ,
get ( client_server ::get_state_events_for_empty_key_route )
. put ( client_server ::send_state_event_for_empty_key_route ) ,
)
2022-04-01 16:00:04 +02:00
. route (
" /_matrix/client/v3/rooms/:room_id/state/:event_type " ,
get ( client_server ::get_state_events_for_empty_key_route )
. put ( client_server ::send_state_event_for_empty_key_route ) ,
)
// These two endpoints allow trailing slashes
. route (
" /_matrix/client/r0/rooms/:room_id/state/:event_type/ " ,
get ( client_server ::get_state_events_for_empty_key_route )
. put ( client_server ::send_state_event_for_empty_key_route ) ,
)
. route (
" /_matrix/client/v3/rooms/:room_id/state/:event_type/ " ,
get ( client_server ::get_state_events_for_empty_key_route )
. put ( client_server ::send_state_event_for_empty_key_route ) ,
)
2022-01-22 13:51:55 +01:00
. ruma_route ( client_server ::sync_events_route )
2023-07-06 10:32:25 +02:00
. ruma_route ( client_server ::sync_events_v4_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( client_server ::get_context_route )
. ruma_route ( client_server ::get_message_events_route )
. ruma_route ( client_server ::search_events_route )
. ruma_route ( client_server ::turn_server_route )
. ruma_route ( client_server ::send_event_to_device_route )
. ruma_route ( client_server ::get_media_config_route )
. ruma_route ( client_server ::create_content_route )
. ruma_route ( client_server ::get_content_route )
. ruma_route ( client_server ::get_content_as_filename_route )
. ruma_route ( client_server ::get_content_thumbnail_route )
. ruma_route ( client_server ::get_devices_route )
. ruma_route ( client_server ::get_device_route )
. ruma_route ( client_server ::update_device_route )
. ruma_route ( client_server ::delete_device_route )
. ruma_route ( client_server ::delete_devices_route )
. ruma_route ( client_server ::get_tags_route )
. ruma_route ( client_server ::update_tag_route )
. ruma_route ( client_server ::delete_tag_route )
. ruma_route ( client_server ::upload_signing_keys_route )
. ruma_route ( client_server ::upload_signatures_route )
. ruma_route ( client_server ::get_key_changes_route )
. ruma_route ( client_server ::get_pushers_route )
. ruma_route ( client_server ::set_pushers_route )
// .ruma_route(client_server::third_party_route)
. ruma_route ( client_server ::upgrade_room_route )
2023-06-25 19:31:40 +02:00
. ruma_route ( client_server ::get_threads_route )
2023-06-26 12:38:51 +02:00
. ruma_route ( client_server ::get_relating_events_with_rel_type_and_event_type_route )
. ruma_route ( client_server ::get_relating_events_with_rel_type_route )
. ruma_route ( client_server ::get_relating_events_route )
2023-07-02 16:06:54 +02:00
. ruma_route ( client_server ::get_hierarchy_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( server_server ::get_server_version_route )
. route (
" /_matrix/key/v2/server " ,
get ( server_server ::get_server_keys_route ) ,
)
. route (
" /_matrix/key/v2/server/:key_id " ,
get ( server_server ::get_server_keys_deprecated_route ) ,
)
. ruma_route ( server_server ::get_public_rooms_route )
. ruma_route ( server_server ::get_public_rooms_filtered_route )
. ruma_route ( server_server ::send_transaction_message_route )
. ruma_route ( server_server ::get_event_route )
2023-02-18 13:20:20 +01:00
. ruma_route ( server_server ::get_backfill_route )
2022-01-20 11:51:31 +01:00
. ruma_route ( server_server ::get_missing_events_route )
. ruma_route ( server_server ::get_event_authorization_route )
. ruma_route ( server_server ::get_room_state_route )
. ruma_route ( server_server ::get_room_state_ids_route )
. ruma_route ( server_server ::create_join_event_template_route )
. ruma_route ( server_server ::create_join_event_v1_route )
. ruma_route ( server_server ::create_join_event_v2_route )
. ruma_route ( server_server ::create_invite_route )
. ruma_route ( server_server ::get_devices_route )
. ruma_route ( server_server ::get_room_information_route )
. ruma_route ( server_server ::get_profile_information_route )
. ruma_route ( server_server ::get_keys_route )
. ruma_route ( server_server ::claim_keys_route )
2022-10-11 22:37:14 +02:00
. route (
" /_matrix/client/r0/rooms/:room_id/initialSync " ,
get ( initial_sync ) ,
)
. route (
" /_matrix/client/v3/rooms/:room_id/initialSync " ,
get ( initial_sync ) ,
)
2024-01-07 21:24:55 -05:00
. route (
" /client/server.json " ,
get ( client_server ::syncv3_client_server_json ) ,
)
. route (
" /.well-known/matrix/client " ,
get ( client_server ::well_known_client_route ) ,
)
. route (
" /.well-known/matrix/server " ,
get ( server_server ::well_known_server_route ) ,
)
2023-07-28 23:47:00 +00:00
. route ( " / " , get ( it_works ) )
2023-06-29 11:20:52 +02:00
. fallback ( not_found )
2021-02-06 15:27:43 +01:00
}
2021-07-19 11:55:39 +02:00
2023-07-29 21:57:41 +00:00
async fn shutdown_signal ( handle : ServerHandle , tx : Sender < ( ) > ) -> Result < ( ) > {
2022-01-20 11:51:31 +01:00
let ctrl_c = async {
signal ::ctrl_c ( )
. await
. expect ( " failed to install Ctrl+C handler " ) ;
} ;
#[ cfg(unix) ]
let terminate = async {
signal ::unix ::signal ( signal ::unix ::SignalKind ::terminate ( ) )
. expect ( " failed to install signal handler " )
. recv ( )
. await ;
} ;
2021-07-19 11:55:39 +02:00
2022-01-20 11:51:31 +01:00
#[ cfg(not(unix)) ]
let terminate = std ::future ::pending ::< ( ) > ( ) ;
2021-07-19 11:55:39 +02:00
2022-02-22 00:26:53 +01:00
let sig : & str ;
2022-01-20 11:51:31 +01:00
tokio ::select! {
2022-02-22 00:26:53 +01:00
_ = ctrl_c = > { sig = " Ctrl+C " ; } ,
_ = terminate = > { sig = " SIGTERM " ; } ,
2022-01-20 11:51:31 +01:00
}
2022-01-22 18:38:39 +01:00
2022-02-22 00:26:53 +01:00
warn! ( " Received {}, shutting down... " , sig ) ;
2023-12-25 20:05:05 -05:00
handle . graceful_shutdown ( Some ( Duration ::from_secs ( 60 ) ) ) ;
2023-03-18 08:58:20 +01:00
services ( ) . globals . shutdown ( ) ;
#[ cfg(feature = " systemd " ) ]
let _ = sd_notify ::notify ( true , & [ sd_notify ::NotifyState ::Stopping ] ) ;
2023-07-29 21:57:41 +00:00
tx . send ( ( ) ) . unwrap ( ) ;
Ok ( ( ) )
2022-01-20 11:51:31 +01:00
}
2021-07-19 11:55:39 +02:00
2022-10-15 00:28:43 +02:00
async fn not_found ( uri : Uri ) -> impl IntoResponse {
warn! ( " Not found: {uri} " ) ;
2022-10-11 22:37:14 +02:00
Error ::BadRequest ( ErrorKind ::Unrecognized , " Unrecognized request " )
}
async fn initial_sync ( _uri : Uri ) -> impl IntoResponse {
2022-10-15 00:28:43 +02:00
Error ::BadRequest (
ErrorKind ::GuestAccessForbidden ,
" Guest access not implemented " ,
)
2022-02-13 13:59:27 +01:00
}
2023-07-28 23:47:00 +00:00
async fn it_works ( ) -> & 'static str {
2023-11-29 21:36:02 -05:00
" hewwo from conduwuit woof! "
2023-07-28 23:47:00 +00:00
}
2022-01-20 11:51:31 +01:00
trait RouterExt {
fn ruma_route < H , T > ( self , handler : H ) -> Self
where
H : RumaHandler < T > ,
T : 'static ;
}
2021-07-19 11:55:39 +02:00
2022-01-20 11:51:31 +01:00
impl RouterExt for Router {
fn ruma_route < H , T > ( self , handler : H ) -> Self
where
H : RumaHandler < T > ,
T : 'static ,
{
2022-01-22 16:58:32 +01:00
handler . add_to_router ( self )
2021-07-19 11:55:39 +02:00
}
}
2022-01-20 11:51:31 +01:00
2022-01-22 16:58:32 +01:00
pub trait RumaHandler < T > {
// Can't transform to a handler without boxing or relying on the nightly-only
// impl-trait-in-traits feature. Moving a small amount of extra logic into the trait
// allows bypassing both.
fn add_to_router ( self , router : Router ) -> Router ;
2022-01-20 11:51:31 +01:00
}
macro_rules ! impl_ruma_handler {
( $( $ty :ident ) , * $(, ) ? ) = > {
#[ axum::async_trait ]
#[ allow(non_snake_case) ]
2022-01-22 13:51:55 +01:00
impl < Req , E , F , Fut , $( $ty , ) * > RumaHandler < ( $( $ty , ) * Ruma < Req > , ) > for F
2022-01-20 11:51:31 +01:00
where
2022-04-06 21:31:29 +02:00
Req : IncomingRequest + Send + 'static ,
2022-01-20 11:51:31 +01:00
F : FnOnce ( $( $ty , ) * Ruma < Req > ) -> Fut + Clone + Send + 'static ,
2022-04-06 21:31:29 +02:00
Fut : Future < Output = Result < Req ::OutgoingResponse , E > >
2022-01-22 16:58:32 +01:00
+ Send ,
2022-01-22 13:51:55 +01:00
E : IntoResponse ,
2023-06-29 11:20:52 +02:00
$( $ty : FromRequestParts < ( ) > + Send + 'static , ) *
2022-01-20 11:51:31 +01:00
{
2022-02-13 12:07:00 +01:00
fn add_to_router ( self , mut router : Router ) -> Router {
2022-04-06 21:31:29 +02:00
let meta = Req ::METADATA ;
2022-01-22 16:58:32 +01:00
let method_filter = method_to_filter ( meta . method ) ;
2022-11-09 18:46:10 +01:00
for path in meta . history . all_paths ( ) {
2022-02-13 11:30:04 +00:00
let handler = self . clone ( ) ;
2022-02-13 12:07:00 +01:00
router = router . route ( path , on ( method_filter , | $( $ty : $ty , ) * req | async move {
2022-02-13 11:30:04 +00:00
handler ( $( $ty , ) * req ) . await . map ( RumaResponse )
2022-02-13 12:07:00 +01:00
} ) )
}
router
2022-01-22 16:58:32 +01:00
}
2022-01-20 11:51:31 +01:00
}
} ;
}
impl_ruma_handler! ( ) ;
impl_ruma_handler! ( T1 ) ;
impl_ruma_handler! ( T1 , T2 ) ;
impl_ruma_handler! ( T1 , T2 , T3 ) ;
impl_ruma_handler! ( T1 , T2 , T3 , T4 ) ;
impl_ruma_handler! ( T1 , T2 , T3 , T4 , T5 ) ;
impl_ruma_handler! ( T1 , T2 , T3 , T4 , T5 , T6 ) ;
impl_ruma_handler! ( T1 , T2 , T3 , T4 , T5 , T6 , T7 ) ;
impl_ruma_handler! ( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 ) ;
2022-01-22 16:58:32 +01:00
fn method_to_filter ( method : Method ) -> MethodFilter {
2022-10-10 14:09:11 +02:00
match method {
2022-01-22 16:58:32 +01:00
Method ::DELETE = > MethodFilter ::DELETE ,
Method ::GET = > MethodFilter ::GET ,
Method ::HEAD = > MethodFilter ::HEAD ,
Method ::OPTIONS = > MethodFilter ::OPTIONS ,
Method ::PATCH = > MethodFilter ::PATCH ,
Method ::POST = > MethodFilter ::POST ,
Method ::PUT = > MethodFilter ::PUT ,
Method ::TRACE = > MethodFilter ::TRACE ,
2022-12-21 10:42:12 +01:00
m = > panic! ( " Unsupported HTTP method: {m:?} " ) ,
2022-10-10 14:09:11 +02:00
}
2022-01-22 16:58:32 +01:00
}
2023-07-26 13:24:44 -07:00
#[ cfg(unix) ]
2023-08-03 14:51:39 -10:00
#[ tracing::instrument(err) ]
2023-07-26 13:24:44 -07:00
fn maximize_fd_limit ( ) -> Result < ( ) , nix ::errno ::Errno > {
use nix ::sys ::resource ::{ getrlimit , setrlimit , Resource } ;
let res = Resource ::RLIMIT_NOFILE ;
2023-08-03 14:51:39 -10:00
let ( soft_limit , hard_limit ) = getrlimit ( res ) ? ;
debug! ( " Current nofile soft limit: {soft_limit} " ) ;
2023-07-26 13:24:44 -07:00
2023-08-03 14:51:39 -10:00
setrlimit ( res , hard_limit , hard_limit ) ? ;
debug! ( " Increased nofile soft limit to {hard_limit} " ) ;
Ok ( ( ) )
2023-07-26 13:24:44 -07:00
}