async-graphql/async-graphql-actix-web/src/session.rs

133 lines
4.2 KiB
Rust
Raw Normal View History

2020-03-31 03:19:18 +00:00
use crate::BoxOnConnectFn;
2020-03-17 09:26:59 +00:00
use actix::{
2020-03-29 12:02:52 +00:00
Actor, ActorContext, ActorFuture, AsyncContext, ContextFutureSpawner, StreamHandler, WrapFuture,
2020-03-17 09:26:59 +00:00
};
2020-03-31 03:19:18 +00:00
use actix_web::HttpRequest;
2020-03-17 09:26:59 +00:00
use actix_web_actors::ws::{Message, ProtocolError, WebsocketContext};
2020-03-29 12:02:52 +00:00
use async_graphql::{ObjectType, Schema, SubscriptionType, WebSocketTransport};
use bytes::Bytes;
use futures::channel::mpsc;
use futures::SinkExt;
2020-03-19 09:20:12 +00:00
use std::time::{Duration, Instant};
2020-03-17 09:26:59 +00:00
pub struct WsSession<Query, Mutation, Subscription> {
2020-03-31 03:19:18 +00:00
req: HttpRequest,
2020-03-29 12:02:52 +00:00
schema: Schema<Query, Mutation, Subscription>,
2020-03-17 09:26:59 +00:00
hb: Instant,
2020-03-29 12:02:52 +00:00
sink: Option<mpsc::Sender<Bytes>>,
2020-03-31 03:19:18 +00:00
on_connect: Option<BoxOnConnectFn<Query, Mutation, Subscription>>,
2020-03-17 09:26:59 +00:00
}
impl<Query, Mutation, Subscription> WsSession<Query, Mutation, Subscription>
where
2020-03-19 09:20:12 +00:00
Query: ObjectType + Send + Sync + 'static,
Mutation: ObjectType + Send + Sync + 'static,
Subscription: SubscriptionType + Send + Sync + 'static,
2020-03-17 09:26:59 +00:00
{
2020-03-31 03:19:18 +00:00
pub fn new(
schema: Schema<Query, Mutation, Subscription>,
req: HttpRequest,
on_connect: Option<BoxOnConnectFn<Query, Mutation, Subscription>>,
) -> Self {
2020-03-17 09:26:59 +00:00
Self {
2020-03-31 03:19:18 +00:00
req,
2020-03-17 09:26:59 +00:00
schema,
hb: Instant::now(),
2020-03-29 12:02:52 +00:00
sink: None,
2020-03-31 03:19:18 +00:00
on_connect,
2020-03-17 09:26:59 +00:00
}
}
2020-03-19 09:20:12 +00:00
fn hb(&self, ctx: &mut WebsocketContext<Self>) {
ctx.run_interval(Duration::new(1, 0), |act, ctx| {
if Instant::now().duration_since(act.hb) > Duration::new(10, 0) {
ctx.stop();
}
});
}
2020-03-17 09:26:59 +00:00
}
impl<Query, Mutation, Subscription> Actor for WsSession<Query, Mutation, Subscription>
where
2020-03-19 09:20:12 +00:00
Query: ObjectType + Sync + Send + 'static,
Mutation: ObjectType + Sync + Send + 'static,
Subscription: SubscriptionType + Send + Sync + 'static,
2020-03-17 09:26:59 +00:00
{
type Context = WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
2020-03-19 09:20:12 +00:00
self.hb(ctx);
2020-03-29 12:02:52 +00:00
let schema = self.schema.clone();
2020-03-31 03:19:18 +00:00
let on_connect = self.on_connect.clone();
let req = self.req.clone();
2020-03-29 12:02:52 +00:00
async move {
2020-03-31 03:19:18 +00:00
let mut builder = schema
2020-03-29 12:02:52 +00:00
.clone()
2020-03-31 03:19:18 +00:00
.subscription_connection(WebSocketTransport::default());
if let Some(on_connect) = on_connect {
builder = on_connect(&req, builder);
}
builder.build().await
2020-03-29 12:02:52 +00:00
}
.into_actor(self)
.then(|(sink, stream), actor, ctx| {
actor.sink = Some(sink);
ctx.add_stream(stream);
async {}.into_actor(actor)
})
.wait(ctx);
2020-03-17 09:26:59 +00:00
}
}
impl<Query, Mutation, Subscription> StreamHandler<Result<Message, ProtocolError>>
for WsSession<Query, Mutation, Subscription>
where
2020-03-19 09:20:12 +00:00
Query: ObjectType + Sync + Send + 'static,
Mutation: ObjectType + Sync + Send + 'static,
Subscription: SubscriptionType + Send + Sync + 'static,
2020-03-17 09:26:59 +00:00
{
fn handle(&mut self, msg: Result<Message, ProtocolError>, ctx: &mut Self::Context) {
let msg = match msg {
Err(_) => {
ctx.stop();
return;
}
Ok(msg) => msg,
};
match msg {
Message::Ping(msg) => {
self.hb = Instant::now();
ctx.pong(&msg);
}
Message::Pong(_) => {
self.hb = Instant::now();
}
Message::Text(s) => {
2020-03-29 12:02:52 +00:00
if let Some(mut sink) = self.sink.clone() {
async move { sink.send(s.into()).await }
.into_actor(self)
.then(|_, actor, _| async {}.into_actor(actor))
.wait(ctx);
2020-03-17 09:26:59 +00:00
}
}
Message::Binary(_) | Message::Close(_) | Message::Continuation(_) => {
ctx.stop();
}
Message::Nop => {}
}
}
}
2020-03-29 12:02:52 +00:00
impl<Query, Mutation, Subscription> StreamHandler<Bytes>
2020-03-17 09:26:59 +00:00
for WsSession<Query, Mutation, Subscription>
where
2020-03-19 09:20:12 +00:00
Query: ObjectType + Send + Sync + 'static,
Mutation: ObjectType + Send + Sync + 'static,
Subscription: SubscriptionType + Send + Sync + 'static,
2020-03-17 09:26:59 +00:00
{
2020-03-29 12:02:52 +00:00
fn handle(&mut self, data: Bytes, ctx: &mut Self::Context) {
ctx.text(unsafe { std::str::from_utf8_unchecked(&data) });
2020-03-17 09:26:59 +00:00
}
}