diff --git a/README.md b/README.md index 338bb9b..7cf9dc5 100644 --- a/README.md +++ b/README.md @@ -167,8 +167,8 @@ class Subscription(graphene.ObjectType): def resolve_count_seconds( - root, - info, + root, + info, up_to=5 ): return Observable.interval(1000)\ @@ -202,4 +202,36 @@ from graphql_ws.django_channels import GraphQLSubscriptionConsumer channel_routing = [ route_class(GraphQLSubscriptionConsumer, path=r"^/subscriptions"), ] -``` \ No newline at end of file +``` + +### Tornado +```python +from asyncio import Queue +from tornado import web, ioloop, websocket + +from graphql_ws.tornado import TornadoSubscriptionServer + + +subscription_server = TornadoSubscriptionServer(schema) + + +class SubscriptionHandler(websocket.WebSocketHandler): + def initialize(self, sub_server): + self.subscription_server = subscription_server + self.queue = Queue() + + def select_subprotocol(self, subprotocols): + return 'graphql-ws' + + def open(self): + ioloop.IOLoop.current().spawn_callback(subscription_server.handle, self) + + async def on_message(self, message): + await self.queue.put(message) + + async def recv(self): + return await self.queue.get() + +app = web.Application([(r"/subscriptions", SubscriptionHandler)]).listen(8000) +ioloop.IOLoop.current().start() +``` diff --git a/examples/tornado/__init__.py b/examples/tornado/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/tornado/app.py b/examples/tornado/app.py new file mode 100644 index 0000000..f8d807d --- /dev/null +++ b/examples/tornado/app.py @@ -0,0 +1,47 @@ +from asyncio import Queue +from tornado import web, ioloop, websocket + +from graphene_tornado.tornado_graphql_handler import TornadoGraphQLHandler + +from graphql_ws.tornado import TornadoSubscriptionServer +from graphql_ws.constants import GRAPHQL_WS + +from .template import render_graphiql +from .schema import schema + + +class GraphiQLHandler(web.RequestHandler): + def get(self): + self.finish(render_graphiql()) + + +class SubscriptionHandler(websocket.WebSocketHandler): + def initialize(self, subscription_server): + self.subscription_server = subscription_server + self.queue = Queue(100) + + def select_subprotocol(self, subprotocols): + return GRAPHQL_WS + + def open(self): + ioloop.IOLoop.current().spawn_callback(self.subscription_server.handle, self) + + async def on_message(self, message): + await self.queue.put(message) + + async def recv(self): + return await self.queue.get() + + +subscription_server = TornadoSubscriptionServer(schema) + +app = web.Application([ + (r"/graphql$", TornadoGraphQLHandler, dict( + schema=schema)), + (r"/subscriptions", SubscriptionHandler, dict( + subscription_server=subscription_server)), + (r"/graphiql$", GraphiQLHandler), +]) + +app.listen(8000) +ioloop.IOLoop.current().start() diff --git a/examples/tornado/requirements.txt b/examples/tornado/requirements.txt new file mode 100644 index 0000000..0eae84e --- /dev/null +++ b/examples/tornado/requirements.txt @@ -0,0 +1,3 @@ +graphql_ws +tornado +graphene>=2.0 diff --git a/examples/tornado/schema.py b/examples/tornado/schema.py new file mode 100644 index 0000000..3c23d00 --- /dev/null +++ b/examples/tornado/schema.py @@ -0,0 +1,34 @@ +import random +import asyncio +import graphene + + +class Query(graphene.ObjectType): + base = graphene.String() + + +class RandomType(graphene.ObjectType): + seconds = graphene.Int() + random_int = graphene.Int() + + +class Subscription(graphene.ObjectType): + count_seconds = graphene.Float(up_to=graphene.Int()) + random_int = graphene.Field(RandomType) + + async def resolve_count_seconds(root, info, up_to=5): + for i in range(up_to): + print("YIELD SECOND", i) + yield i + await asyncio.sleep(1.) + yield up_to + + async def resolve_random_int(root, info): + i = 0 + while True: + yield RandomType(seconds=i, random_int=random.randint(0, 500)) + await asyncio.sleep(1.) + i += 1 + + +schema = graphene.Schema(query=Query, subscription=Subscription) diff --git a/examples/tornado/template.py b/examples/tornado/template.py new file mode 100644 index 0000000..0b74e96 --- /dev/null +++ b/examples/tornado/template.py @@ -0,0 +1,125 @@ + +from string import Template + + +def render_graphiql(): + return Template(''' + + +
+ +