You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Move the GraphQL schema to its own crate
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -2592,6 +2592,17 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mas-graphql"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-graphql",
|
||||||
|
"mas-axum-utils",
|
||||||
|
"sqlx",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mas-handlers"
|
name = "mas-handlers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2611,6 +2622,7 @@ dependencies = [
|
|||||||
"mas-axum-utils",
|
"mas-axum-utils",
|
||||||
"mas-data-model",
|
"mas-data-model",
|
||||||
"mas-email",
|
"mas-email",
|
||||||
|
"mas-graphql",
|
||||||
"mas-http",
|
"mas-http",
|
||||||
"mas-iana",
|
"mas-iana",
|
||||||
"mas-jose",
|
"mas-jose",
|
||||||
@ -2630,7 +2642,6 @@ dependencies = [
|
|||||||
"sqlx",
|
"sqlx",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
17
crates/graphql/Cargo.toml
Normal file
17
crates/graphql/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "mas-graphql"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Quentin Gliech <quenting@element.io>"]
|
||||||
|
edition = "2021"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-graphql = "4.0.16"
|
||||||
|
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "postgres"] }
|
||||||
|
tokio = { version = "1.21.2", features = ["time"] }
|
||||||
|
tokio-stream = "0.1.11"
|
||||||
|
|
||||||
|
mas-axum-utils = { path = "../axum-utils" }
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "schema"
|
27
crates/graphql/src/bin/schema.rs
Normal file
27
crates/graphql/src/bin/schema.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![deny(
|
||||||
|
clippy::all,
|
||||||
|
clippy::str_to_string,
|
||||||
|
rustdoc::broken_intra_doc_links,
|
||||||
|
clippy::future_not_send
|
||||||
|
)]
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let schema = mas_graphql::schema_builder().finish();
|
||||||
|
println!("{}", schema.sdl());
|
||||||
|
}
|
108
crates/graphql/src/lib.rs
Normal file
108
crates/graphql/src/lib.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![deny(
|
||||||
|
clippy::all,
|
||||||
|
clippy::str_to_string,
|
||||||
|
rustdoc::broken_intra_doc_links,
|
||||||
|
clippy::future_not_send
|
||||||
|
)]
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)]
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use async_graphql::Context;
|
||||||
|
use mas_axum_utils::SessionInfo;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
use tokio_stream::{Stream, StreamExt};
|
||||||
|
|
||||||
|
pub type Schema = async_graphql::Schema<Query, Mutation, Subscription>;
|
||||||
|
pub type SchemaBuilder = async_graphql::SchemaBuilder<Query, Mutation, Subscription>;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn schema_builder() -> SchemaBuilder {
|
||||||
|
async_graphql::Schema::build(Query::new(), Mutation::new(), Subscription::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Query {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Query {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_graphql::Object]
|
||||||
|
impl Query {
|
||||||
|
/// A simple property which uses the DB pool and the current session
|
||||||
|
async fn username(&self, ctx: &Context<'_>) -> Result<Option<String>, async_graphql::Error> {
|
||||||
|
let database = ctx.data::<PgPool>()?;
|
||||||
|
let session_info = ctx.data::<SessionInfo>()?;
|
||||||
|
let mut conn = database.acquire().await?;
|
||||||
|
let session = session_info.load_session(&mut conn).await?;
|
||||||
|
|
||||||
|
Ok(session.map(|s| s.user.username))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Mutation {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mutation {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_graphql::Object]
|
||||||
|
impl Mutation {
|
||||||
|
/// A dummy mutation so that the mutation object is not empty
|
||||||
|
async fn hello(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Subscription {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Subscription {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_graphql::Subscription]
|
||||||
|
impl Subscription {
|
||||||
|
/// A dump subscription to try out the websocket
|
||||||
|
async fn integers(&self, #[graphql(default = 1)] step: i32) -> impl Stream<Item = i32> {
|
||||||
|
let mut value = 0;
|
||||||
|
tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(Duration::from_secs(1)))
|
||||||
|
.map(move |_| {
|
||||||
|
value += step;
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ license = "Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# Async runtime
|
# Async runtime
|
||||||
tokio = { version = "1.21.2", features = ["macros"] }
|
tokio = { version = "1.21.2", features = ["macros"] }
|
||||||
tokio-stream = "0.1.11"
|
|
||||||
futures-util = "0.3.25"
|
futures-util = "0.3.25"
|
||||||
|
|
||||||
# Logging and tracing
|
# Logging and tracing
|
||||||
@ -56,6 +55,7 @@ oauth2-types = { path = "../oauth2-types" }
|
|||||||
mas-axum-utils = { path = "../axum-utils", default-features = false }
|
mas-axum-utils = { path = "../axum-utils", default-features = false }
|
||||||
mas-data-model = { path = "../data-model" }
|
mas-data-model = { path = "../data-model" }
|
||||||
mas-email = { path = "../email" }
|
mas-email = { path = "../email" }
|
||||||
|
mas-graphql = { path = "../graphql" }
|
||||||
mas-http = { path = "../http", default-features = false }
|
mas-http = { path = "../http", default-features = false }
|
||||||
mas-iana = { path = "../iana" }
|
mas-iana = { path = "../iana" }
|
||||||
mas-jose = { path = "../jose" }
|
mas-jose = { path = "../jose" }
|
||||||
|
@ -22,7 +22,7 @@ use mas_router::UrlBuilder;
|
|||||||
use mas_templates::Templates;
|
use mas_templates::Templates;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::{GraphQLSchema, MatrixHomeserver};
|
use crate::MatrixHomeserver;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
@ -34,7 +34,7 @@ pub struct AppState {
|
|||||||
pub mailer: Mailer,
|
pub mailer: Mailer,
|
||||||
pub homeserver: MatrixHomeserver,
|
pub homeserver: MatrixHomeserver,
|
||||||
pub policy_factory: Arc<PolicyFactory>,
|
pub policy_factory: Arc<PolicyFactory>,
|
||||||
pub graphql_schema: GraphQLSchema,
|
pub graphql_schema: mas_graphql::Schema,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRef<AppState> for PgPool {
|
impl FromRef<AppState> for PgPool {
|
||||||
@ -43,7 +43,7 @@ impl FromRef<AppState> for PgPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRef<AppState> for GraphQLSchema {
|
impl FromRef<AppState> for mas_graphql::Schema {
|
||||||
fn from_ref(input: &AppState) -> Self {
|
fn from_ref(input: &AppState) -> Self {
|
||||||
input.graphql_schema.clone()
|
input.graphql_schema.clone()
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::{borrow::Cow, str::FromStr, time::Duration};
|
use std::{borrow::Cow, str::FromStr};
|
||||||
|
|
||||||
use async_graphql::{
|
use async_graphql::{
|
||||||
extensions::{ApolloTracing, Tracing},
|
extensions::{ApolloTracing, Tracing},
|
||||||
futures_util::TryStreamExt,
|
|
||||||
http::{
|
http::{
|
||||||
playground_source, GraphQLPlaygroundConfig, MultipartOptions, WebSocketProtocols,
|
playground_source, GraphQLPlaygroundConfig, MultipartOptions, WebSocketProtocols,
|
||||||
WsMessage, ALL_WEBSOCKET_PROTOCOLS,
|
WsMessage, ALL_WEBSOCKET_PROTOCOLS,
|
||||||
},
|
},
|
||||||
Context, Data, EmptyMutation,
|
Data,
|
||||||
};
|
};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{
|
extract::{
|
||||||
@ -32,19 +31,19 @@ use axum::{
|
|||||||
Json, TypedHeader,
|
Json, TypedHeader,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::PrivateCookieJar;
|
use axum_extra::extract::PrivateCookieJar;
|
||||||
use futures_util::{SinkExt, Stream, StreamExt};
|
use futures_util::{SinkExt, StreamExt, TryStreamExt};
|
||||||
use headers::{ContentType, Header, HeaderValue};
|
use headers::{ContentType, Header, HeaderValue};
|
||||||
use hyper::header::{CACHE_CONTROL, SEC_WEBSOCKET_PROTOCOL};
|
use hyper::header::{CACHE_CONTROL, SEC_WEBSOCKET_PROTOCOL};
|
||||||
use mas_axum_utils::{FancyError, SessionInfo, SessionInfoExt};
|
use mas_axum_utils::{FancyError, SessionInfoExt};
|
||||||
|
use mas_graphql::Schema;
|
||||||
use mas_keystore::Encrypter;
|
use mas_keystore::Encrypter;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tracing::{info_span, Instrument};
|
use tracing::{info_span, Instrument};
|
||||||
|
|
||||||
pub type Schema = async_graphql::Schema<Query, EmptyMutation, Subscription>;
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn schema(pool: &PgPool) -> Schema {
|
pub fn schema(pool: &PgPool) -> Schema {
|
||||||
async_graphql::Schema::build(Query::new(pool), EmptyMutation, Subscription)
|
mas_graphql::schema_builder()
|
||||||
|
.data(pool.clone())
|
||||||
.extension(Tracing)
|
.extension(Tracing)
|
||||||
.extension(ApolloTracing)
|
.extension(ApolloTracing)
|
||||||
.finish()
|
.finish()
|
||||||
@ -212,40 +211,3 @@ pub async fn playground() -> impl IntoResponse {
|
|||||||
.with_setting("request.credentials", "include"),
|
.with_setting("request.credentials", "include"),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Query {
|
|
||||||
database: PgPool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Query {
|
|
||||||
fn new(pool: &PgPool) -> Self {
|
|
||||||
Self {
|
|
||||||
database: pool.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_graphql::Object]
|
|
||||||
impl Query {
|
|
||||||
async fn username(&self, ctx: &Context<'_>) -> Result<Option<String>, async_graphql::Error> {
|
|
||||||
let mut conn = self.database.acquire().await?;
|
|
||||||
let session_info = ctx.data::<SessionInfo>()?;
|
|
||||||
let session = session_info.load_session(&mut conn).await?;
|
|
||||||
|
|
||||||
Ok(session.map(|s| s.user.username))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Subscription;
|
|
||||||
|
|
||||||
#[async_graphql::Subscription]
|
|
||||||
impl Subscription {
|
|
||||||
async fn integers(&self, #[graphql(default = 1)] step: i32) -> impl Stream<Item = i32> {
|
|
||||||
let mut value = 0;
|
|
||||||
tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(Duration::from_secs(1)))
|
|
||||||
.map(move |_| {
|
|
||||||
value += step;
|
|
||||||
value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -56,10 +56,7 @@ mod views;
|
|||||||
|
|
||||||
pub use compat::MatrixHomeserver;
|
pub use compat::MatrixHomeserver;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{app_state::AppState, graphql::schema as graphql_schema};
|
||||||
app_state::AppState,
|
|
||||||
graphql::{schema as graphql_schema, Schema as GraphQLSchema},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn empty_router<S, B>(state: Arc<S>) -> Router<S, B>
|
pub fn empty_router<S, B>(state: Arc<S>) -> Router<S, B>
|
||||||
@ -87,7 +84,7 @@ where
|
|||||||
<B as HttpBody>::Data: Into<Bytes>,
|
<B as HttpBody>::Data: Into<Bytes>,
|
||||||
<B as HttpBody>::Error: std::error::Error + Send + Sync,
|
<B as HttpBody>::Error: std::error::Error + Send + Sync,
|
||||||
S: Send + Sync + 'static,
|
S: Send + Sync + 'static,
|
||||||
GraphQLSchema: FromRef<S>,
|
mas_graphql::Schema: FromRef<S>,
|
||||||
Encrypter: FromRef<S>,
|
Encrypter: FromRef<S>,
|
||||||
{
|
{
|
||||||
let mut router = Router::with_state_arc(state)
|
let mut router = Router::with_state_arc(state)
|
||||||
@ -344,7 +341,7 @@ where
|
|||||||
Templates: FromRef<S>,
|
Templates: FromRef<S>,
|
||||||
Mailer: FromRef<S>,
|
Mailer: FromRef<S>,
|
||||||
MatrixHomeserver: FromRef<S>,
|
MatrixHomeserver: FromRef<S>,
|
||||||
GraphQLSchema: FromRef<S>,
|
mas_graphql::Schema: FromRef<S>,
|
||||||
{
|
{
|
||||||
let healthcheck_router = healthcheck_router(state.clone());
|
let healthcheck_router = healthcheck_router(state.clone());
|
||||||
let discovery_router = discovery_router(state.clone());
|
let discovery_router = discovery_router(state.clone());
|
||||||
|
@ -63,9 +63,11 @@ impl<B> OnResponse<Response<B>> for OnHttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "aws-sdk")]
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct OnAwsResponse;
|
pub struct OnAwsResponse;
|
||||||
|
|
||||||
|
#[cfg(feature = "aws-sdk")]
|
||||||
impl OnResponse<aws_smithy_http::operation::Response> for OnAwsResponse {
|
impl OnResponse<aws_smithy_http::operation::Response> for OnAwsResponse {
|
||||||
fn on_response(
|
fn on_response(
|
||||||
&self,
|
&self,
|
||||||
|
Reference in New Issue
Block a user