Exemplo n.º 1
0
def server(module, host, port):
    sys.path.append(os.getcwd())

    reloader = hupper.start_reloader("strawberry.cli.run", verbose=False)

    schema_module = importlib.import_module(module)

    reloader.watch_files([schema_module.__file__])

    app = Starlette(debug=True)

    app.add_middleware(CORSMiddleware,
                       allow_headers=["*"],
                       allow_origins=["*"],
                       allow_methods=["*"])

    graphql_app = GraphQL(schema_module.schema, debug=True)

    paths = ["/", "/graphql"]

    for path in paths:
        app.add_route(path, graphql_app)
        app.add_websocket_route(path, graphql_app)

    print(f"Running strawberry on http://{host}:{port}/ 🍓")

    uvicorn.run(app, host=host, port=port, log_level="error")
Exemplo n.º 2
0
def create_app():
    app = Starlette()
    app.add_route("/auth", with_auth, methods=["GET"])
    app.add_route("/no-auth", without_auth, methods=["GET"])
    app.add_websocket_route("/ws-auth", ws_with_auth)
    app.add_websocket_route("/ws-no-auth", ws_without_auth)
    return app
Exemplo n.º 3
0
def server(schema, host, port, app_dir):
    sys.path.insert(0, app_dir)

    try:
        schema_symbol = import_module_symbol(schema,
                                             default_symbol_name="schema")
    except (ImportError, AttributeError) as exc:
        message = str(exc)
        raise click.BadArgumentUsage(message)

    if not isinstance(schema_symbol, Schema):
        message = "The `schema` must be an instance of strawberry.Schema"
        raise click.BadArgumentUsage(message)

    reloader = hupper.start_reloader("strawberry.cli.run", verbose=False)
    schema_module = importlib.import_module(schema_symbol.__module__)
    reloader.watch_files([schema_module.__file__])

    app = Starlette(debug=True)
    app.add_middleware(CORSMiddleware,
                       allow_headers=["*"],
                       allow_origins=["*"],
                       allow_methods=["*"])

    graphql_app = GraphQL(schema_symbol, debug=True)

    paths = ["/", "/graphql"]
    for path in paths:
        app.add_route(path, graphql_app)
        app.add_websocket_route(path, graphql_app)

    print(f"Running strawberry on http://{host}:{port}/ 🍓")
    uvicorn.run(app, host=host, port=port, log_level="error")
Exemplo n.º 4
0
class Server:
    """
    `Server` is a thin wrapper around a Starlette application. Rather than have the Server inherit
    the Starlette application class we choose to forward specific methods. This gives us greater control
    over the sufrace area of the application when used with the jab harness as well as leaves open
    the option to break away from using the Starlette application itself and instead begin to use the
    starlette toolkit.
    """

    def __init__(self, host: Optional[str] = None, port: Optional[int] = None, debug: bool = False) -> None:
        self._app = Starlette(debug)
        self._host = host
        self._port = port

    def add_route(self, fn: Handler, rule: str, **options: Any) -> None:
        self._app.add_route(rule, fn, **options)

    def add_websocket_route(self, fn: WebSocketHandler, rule: str, **options: Any) -> None:
        self._app.add_websocket_route(rule, fn, **options)

    async def asgi(self, scope: dict, receive: Receive, send: Send) -> None:
        """
        Exposes the ASGI interface of the Starlette application to be used with your favorite ASGI server.
        """
        await self._app(scope, receive, send)  # pragma: no cover

    async def run(self) -> None:
        """
        Runs the app inside of uvicorn inside of the jab harness.

        NOTE
        ----
        Despite the async definition this function immediately blocks. It's an ugly
        vestige of when jab did not support an ASGI interface itself and the jab ASGI interface should
        always be used instead of it.
        """
        uvicorn.run(self._app, host=self._host or "0.0.0.0", port=self._port or 8000, lifespan="on")

    @property
    def starlette(self) -> Starlette:
        """
        Provides access to the underlying Starlette application.
        Useful in conjunction with `starlette.TestClient`.
        """
        return self._app

    @property
    def jab(self) -> Callable:
        """
        Provides a jab constructor to incorporate an already instantiated Server object.
        """

        def constructor() -> Server:
            return self

        return constructor
Exemplo n.º 5
0
def main() -> None:
    ip = get_local_ip()

    app = Starlette()

    graphql_app = GraphQL(schema)

    app.add_route("/graphql", graphql_app)
    app.add_websocket_route("/graphql", graphql_app)

    typer.echo(f"App running on http://{ip}:8000/graphql")

    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="error")
Exemplo n.º 6
0
def test_app_add_websocket_route():
    app = Starlette()

    async def websocket_endpoint(session):
        await session.accept()
        await session.send_text("Hello, world!")
        await session.close()

    app.add_websocket_route("/ws", websocket_endpoint)
    client = TestClient(app)

    with client.websocket_connect("/ws") as session:
        text = session.receive_text()
        assert text == "Hello, world!"
Exemplo n.º 7
0
def make_app(BASE):
    class CatchAll(BaseHTTPMiddleware):
        async def dispatch(self, request: Request, handler):
            request.scope["path"] = BASE  # TODO subscriptions path
            return await handler(request)

    app = Starlette(debug=True)

    app.add_middleware(CORSMiddleware,
                       allow_headers=["*"],
                       allow_origins=["*"],
                       allow_methods=["*"])

    graphql_app = GraphQL(schema, debug=True)

    app.add_route(BASE, graphql_app)
    app.add_websocket_route(BASE, graphql_app)
    app = CatchAll(app)
    return app
Exemplo n.º 8
0
class NeolithServer:

    def __init__(self):
        self.loop = None
        self.server = None
        self.irc = None
        self.sessions = {}
        self.channels = Channels()
        self.secret_key = os.urandom(32)
        self.name = settings.SERVER_NAME
        if settings.PUBLIC_CHANNEL:
            self.channels.add(Channel(name=settings.PUBLIC_CHANNEL, topic='', protected=True, encrypted=False))
        self.web = Starlette(debug=True)
        self.web.add_event_handler('startup', self.startup)
        self.web.add_event_handler('shutdown', self.shutdown)
        self.web.add_route('/api', self.web_handler, methods=['GET', 'POST'])
        self.web.add_websocket_route('/ws', self.websocket_handler)
        # Server static files
        static_dir = os.path.join(os.path.dirname(__file__), 'static')
        self.web.mount('/static', StaticFiles(directory=static_dir))
        if settings.ENABLE_WEB_CLIENT:
            self.web.add_route('/', client, methods=['GET'])
        if settings.ENABLE_DOCS:
            self.web.add_route('/docs', docs, methods=['GET'])
        if settings.ENABLE_SIGNUP:
            self.web.add_route('/signup', signup, methods=['GET', 'POST'])

    async def startup(self):
        dorm.setup(settings.DATABASE, models=[Account])
        print('Starting binary protocol server on {}:{}'.format(settings.SOCKET_BIND, settings.SOCKET_PORT))
        # Careful not to use the event loop until after uvicorn starts it, since it may swap in uvloop.
        self.loop = asyncio.get_event_loop()
        self.server = await self.loop.create_server(lambda: SocketSession(self), settings.SOCKET_BIND,
            settings.SOCKET_PORT)
        if settings.ENABLE_IRC:
            print('Starting IRC server on {}:{}'.format(settings.IRC_BIND, settings.IRC_PORT))
            self.irc = await self.loop.create_server(lambda: IRCSession(self), settings.IRC_BIND, settings.IRC_PORT)

    async def shutdown(self):
        print('Stopping binary protocol server')
        self.server.close()
        if self.irc:
            self.irc.close()

    async def web_handler(self, request):
        session_token = request.headers.get('x-neolith-session')
        session = self.get(token=session_token, default=WebSession())
        if request.method == 'GET':
            return JSONResponse([tx.to_dict() for tx in await session.events()])
        elif request.method == 'POST':
            session.hostname = request.client.host
            if not session.ident:
                await self.connected(session)
            tx = Transaction(await request.json())
            response = await self.handle(session, tx, send=False)
            return JSONResponse(response.to_dict())
        else:
            return JSONResponse({'error': 'Invalid HTTP method.'}, status_code=405)

    async def websocket_handler(self, websocket, **kwargs):
        await websocket.accept()

        session = WebSocketSession(websocket)
        session.hostname = websocket.client.host

        await self.connected(session)

        try:
            while True:
                tx = Transaction(await websocket.receive_json())
                await self.handle(session, tx)
        except WebSocketDisconnect:
            print('websocket disconnected')
        finally:
            await self.disconnected(session)

    async def handle(self, session, transaction, send=True):
        print(session, '-->', transaction.to_dict())
        response = transaction.response()
        for packet in transaction.packets:
            assert isinstance(packet, ClientPacket)
            try:
                if packet.requires_auth and not session.authenticated:
                    raise ProtocolError('This request requires authentication.')
                response.add(await packet.handle(self, session))
            except ProtocolError as e:
                response.error = str(e)
        if send and not response.empty:
            await session.send(response)
        return response

    async def connected(self, session):
        print('New connection - {}'.format(session))
        session.ident = binascii.hexlify(os.urandom(16)).decode('ascii')
        session.token = binascii.hexlify(os.urandom(16)).decode('ascii')
        self.sessions[session.ident] = session

    async def disconnected(self, session):
        if session.authenticated:
            session.authenticated = False
            for channel in self.channels:
                if session in channel.sessions:
                    channel.remove(session)
                    await channel.send(ChannelLeave(channel=channel.name, user=session))
            await self.broadcast(UserLeft(user=session))
        if session.ident in self.sessions:
            del self.sessions[session.ident]

    def start(self):
        uvicorn.run(self.web, host=settings.WEB_BIND, port=settings.WEB_PORT)

    async def broadcast(self, message):
        for session in self.sessions.values():
            if session.authenticated:
                await session.send(message)

    async def authenticate(self, session):
        if session.authenticated:
            raise ProtocolError('Session is already authenticated.')
        if self.get(nickname=session.nickname, authenticated=True):
            raise ProtocolError('This nickname is already in use.')
        # XXX: where should this go? maybe a new task to be executed next time through the loop?
        await self.broadcast(UserJoined(user=session))
        if settings.PUBLIC_CHANNEL and settings.AUTO_JOIN:
            channel = self.channels[settings.PUBLIC_CHANNEL]
            channel.add(session)
            await channel.send(ChannelJoin(channel=settings.PUBLIC_CHANNEL, user=session))
        # Authenticate the session after sending the joins, so we don't send joins before the login response.
        print('Authenticated {}'.format(session))
        session.authenticated = True
        return session.ident

    def find(self, **kwargs):
        for session in self.sessions.values():
            match = True
            for field, value in kwargs.items():
                if getattr(session, field) != value:
                    match = False
            if match:
                yield session

    def get(self, **kwargs):
        default = kwargs.pop('default', None)
        for session in self.find(**kwargs):
            return session
        return default
Exemplo n.º 9
0
import os

from starlette.applications import Starlette
from starlette.middleware.cors import CORSMiddleware

from strawberry import Schema
from strawberry.asgi import GraphQL
from strawberry.cli.constants import DEBUG_SERVER_SCHEMA_ENV_VAR_KEY
from strawberry.utils.importer import import_module_symbol


app = Starlette(debug=True)
app.add_middleware(
    CORSMiddleware, allow_headers=["*"], allow_origins=["*"], allow_methods=["*"]
)

schema_import_string = os.environ[DEBUG_SERVER_SCHEMA_ENV_VAR_KEY]
schema_symbol = import_module_symbol(schema_import_string, default_symbol_name="schema")

assert isinstance(schema_symbol, Schema)
graphql_app = GraphQL(schema_symbol, debug=True)

paths = ["/", "/graphql"]
for path in paths:
    app.add_route(path, graphql_app)
    app.add_websocket_route(path, graphql_app)
Exemplo n.º 10
0
@SUBSCRIPTION.field("count")
def count(number, _info, **_kwargs):
    """returns current count number, starting at 1"""
    return number + 1


@APP.on_event("startup")
async def startup():
    """initialization steps"""
    await init_db()


@APP.on_event("shutdown")
async def shutdown():
    """clean up on shutdown"""
    await close_connections()

SCHEMA = make_executable_schema(SCHEMA, [MUTATION, QUERY, SUBSCRIPTION, POST])

GRAPHQL_SERVER = GraphQL(
    SCHEMA,
    debug=True,
    extensions=[ApolloTracingExtension],
)


APP.add_route("/graphql/", GRAPHQL_SERVER)
APP.add_websocket_route("/graphql/", GRAPHQL_SERVER)
APP.debug = True
Exemplo n.º 11
0
from src.resolvers.HeroSkill import hero_skill
from src.resolvers.MoveType import move_type
from src.resolvers.Rarity import rarity
from src.resolvers.WeaponType import weapon_type
from src.resolvers.Query import query

# SCHEMA DEFINITION
type_defs = load_schema_from_path("src/schema.graphql")


class LoaderGraphQL(GraphQL):
    async def context_for_request(self, request: Any, data: Any) -> Any:
        return {
            "loaders": {
                "base_stats_loader": BaseStatsLoader(),
                "heroes_loader": HeroesLoader(),
                "skills_loader": SkillsLoader(),
            },
            "request": request,
        }


schema = make_executable_schema(
    type_defs,
    [query, hero, hero_skill, weapon_type, move_type, date_scalar, rarity])
graphql_server = LoaderGraphQL(schema)

app = Starlette()
app.add_route("/", graphql_server)
app.add_websocket_route("/", graphql_server)