forked from graphql-python/graphql-ws
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved codebase. Isolated modules (aiohttp, gevent) so they don’t c…
…ollide
- Loading branch information
1 parent
b3e5459
commit 927ca27
Showing
21 changed files
with
307 additions
and
747 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
graphql_ws | ||
aiohttp>=2.1.0 | ||
graphene>=2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
graphql_ws | ||
gevent | ||
flask | ||
flask_graphql | ||
flask_sockets | ||
graphene>=2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import random | ||
import graphene | ||
from rx import Observable | ||
|
||
|
||
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.Int(up_to=graphene.Int()) | ||
|
||
random_int = graphene.Field(RandomType) | ||
|
||
def resolve_count_seconds(root, info, up_to=5): | ||
return Observable.interval(1000)\ | ||
.map(lambda i: "{0}".format(i))\ | ||
.take_while(lambda i: int(i) <= up_to) | ||
|
||
def resolve_random_int(root, info): | ||
return Observable.interval(1000).map(lambda i: RandomType(seconds=i, random_int=random.randint(0, 500))) | ||
|
||
|
||
schema = graphene.Schema(query=Query, subscription=Subscription) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Submodule graphql
deleted from
ebcd7f
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,13 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
"""Top-level package for GraphQL AioWS.""" | ||
"""Top-level package for GraphQL WS.""" | ||
|
||
__author__ = """Syrus Akbary""" | ||
__email__ = '[email protected]' | ||
__version__ = '0.1.0' | ||
|
||
|
||
from .observable_aiter import setup_observable_extension | ||
from .server import WebSocketSubscriptionServer | ||
from .gevent_server import GeventSubscriptionServer | ||
from .base import BaseConnectionContext, BaseSubscriptionServer | ||
|
||
setup_observable_extension() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
from inspect import isawaitable, isasyncgen | ||
|
||
from asyncio import ensure_future | ||
from aiohttp import WSMsgType | ||
from graphql.execution.executors.asyncio import AsyncioExecutor | ||
|
||
from .base import ConnectionClosedException, BaseConnectionContext, BaseSubscriptionServer | ||
|
||
from .constants import ( | ||
GQL_CONNECTION_ACK, | ||
GQL_CONNECTION_ERROR, | ||
GQL_COMPLETE | ||
) | ||
|
||
|
||
class AiohttpConnectionContext(BaseConnectionContext): | ||
async def receive(self): | ||
msg = await self.ws.receive() | ||
if msg.type == WSMsgType.TEXT: | ||
return msg.data | ||
elif msg.type == WSMsgType.ERROR: | ||
raise ConnectionClosedException() | ||
|
||
async def send(self, data): | ||
if self.closed: | ||
return | ||
await self.ws.send_str(data) | ||
|
||
@property | ||
def closed(self): | ||
return self.ws.closed | ||
|
||
async def close(self, code): | ||
await self.ws.close(code) | ||
|
||
|
||
class AiohttpSubscriptionServer(BaseSubscriptionServer): | ||
|
||
def get_graphql_params(self, *args, **kwargs): | ||
params = super(AiohttpSubscriptionServer, | ||
self).get_graphql_params(*args, **kwargs) | ||
return dict(params, executor=AsyncioExecutor()) | ||
|
||
async def handle(self, ws): | ||
connection_context = AiohttpConnectionContext(ws) | ||
await self.on_open(connection_context) | ||
while True: | ||
try: | ||
if connection_context.closed: | ||
raise ConnectionClosedException() | ||
message = await connection_context.receive() | ||
except ConnectionClosedException: | ||
self.on_close(connection_context) | ||
return | ||
|
||
ensure_future(self.on_message(connection_context, message)) | ||
|
||
async def on_open(self, connection_context): | ||
pass | ||
|
||
def on_close(self, connection_context): | ||
remove_operations = list(connection_context.operations.keys()) | ||
for op_id in remove_operations: | ||
self.unsubscribe(connection_context, op_id) | ||
|
||
async def on_connect(self, connection_context, payload): | ||
pass | ||
|
||
async def on_connection_init(self, connection_context, op_id, payload): | ||
try: | ||
await self.on_connect(connection_context, payload) | ||
await self.send_message(connection_context, op_type=GQL_CONNECTION_ACK) | ||
|
||
# if self.keep_alive: | ||
# await self.send_message(connection_context, | ||
# op_type=GQL_CONNECTION_KEEP_ALIVE) | ||
except Exception as e: | ||
await self.send_error(connection_context, op_id, e, GQL_CONNECTION_ERROR) | ||
await connection_context.close(1011) | ||
|
||
async def on_connection_terminate(self, connection_context, op_id): | ||
await connection_context.close(1011) | ||
|
||
async def on_start(self, connection_context, op_id, params): | ||
execution_result = self.execute(return_promise=True, **params) | ||
|
||
if isawaitable(execution_result): | ||
execution_result = await execution_result | ||
|
||
if not hasattr(execution_result, '__aiter__'): | ||
await self.send_execution_result(connection_context, op_id, execution_result) | ||
else: | ||
iterator = await execution_result.__aiter__() | ||
connection_context.register_operation(op_id, iterator) | ||
async for single_result in iterator: | ||
if not connection_context.has_operation(op_id): | ||
break | ||
await self.send_execution_result(connection_context, op_id, single_result) | ||
await self.send_message(connection_context, op_id, GQL_COMPLETE) | ||
|
||
async def on_stop(self, connection_context, op_id): | ||
self.unsubscribe(connection_context, op_id) |
Oops, something went wrong.