Exemple #1
0
async def bancho_handler(conn: Connection) -> bytes:
    if ('User-Agent' not in conn.headers
            or conn.headers['User-Agent'] != 'osu!'):
        return

    # check for 'osu-token' in the headers.
    # if it's not there, this is a login request.

    if 'osu-token' not in conn.headers:
        # login is a bit of a special case,
        # so we'll handle it separately.
        async with glob.players._lock:
            resp, token = await login(conn.body, conn.headers['X-Real-IP'],
                                      conn.headers)

        conn.add_resp_header(f'cho-token: {token}')
        return resp

    # get the player from the specified osu token.
    player = await glob.players.get(token=conn.headers['osu-token'])

    if not player:
        # token was not found; changes are, we just restarted
        # the server. just tell their client to re-connect.
        return packets.restartServer(0)

    # bancho connections can be comprised of multiple packets;
    # our reader is designed to iterate through them individually,
    # allowing logic to be implemented around the actual handler.

    # NOTE: the reader will internally discard any
    # packets whose logic has not been defined.
    # TODO: why is the packet reader async lol
    async for packet in BanchoPacketReader(conn.body):
        await packet.handle(player)

        if glob.config.debug:
            log(f'{packet.type!r}', Ansi.LMAGENTA)

    player.last_recv_time = time.time()

    # TODO: this could probably be done better?
    resp = bytearray()

    while not player.queue_empty():
        # read all queued packets into stream
        resp += player.dequeue()

    conn.add_resp_header('Content-Type: text/html; charset=UTF-8')
    resp = bytes(resp)

    # even if the packet is empty, we have to
    # send back an empty response so the client
    # knows it was successfully delivered.
    return resp
Exemple #2
0
async def bancho_handler(conn: Connection) -> bytes:
    if ('User-Agent' not in conn.headers
            or conn.headers['User-Agent'] != 'osu!'):
        return

    # check for 'osu-token' in the headers.
    # if it's not there, this is a login request.

    if 'osu-token' not in conn.headers:
        # login is a bit of a special case,
        # so we'll handle it separately.
        async with glob.players._lock:
            resp, token = await login(conn.body, conn.headers['X-Real-IP'])

        conn.add_resp_header(f'cho-token: {token}')
        return resp

    # get the player from the specified osu token.
    player = glob.players.get(token=conn.headers['osu-token'])

    if not player:
        # token was not found; changes are, we just restarted
        # the server. just tell their client to re-connect.
        return packets.notification('Server is restarting') + \
               packets.restartServer(0) # send 0ms since server is up

    # restricted users may only use certain packet handlers.
    if not player.restricted:
        packet_map = glob.bancho_packets['all']
    else:
        packet_map = glob.bancho_packets['restricted']

    # bancho connections can be comprised of multiple packets;
    # our reader is designed to iterate through them individually,
    # allowing logic to be implemented around the actual handler.

    # NOTE: the reader will internally discard any
    # packets whose logic has not been defined.
    packets_read = []
    for packet in BanchoPacketReader(conn.body, packet_map):
        await packet.handle(player)
        packets_read.append(packet.type)

    if glob.config.debug:
        packets_str = ', '.join([p.name for p in packets_read]) or 'None'
        log(f'[BANCHO] {player} | {packets_str}.', AnsiRGB(0xff68ab))

    player.last_recv_time = time.time()
    conn.add_resp_header('Content-Type: text/html; charset=UTF-8')
    return player.dequeue() or b''
Exemple #3
0
async def get_banner(conn: Connection) -> Optional[bytes]:
    filename = conn.path[9:]

    if '.' in filename:
        # user id & file extension provided
        path = BANNERS_PATH / filename
        if not path.exists():
            path = DEFAULT_BANNER
    elif filename not in ('', 'favicon.ico'):
        # user id provided - determine file extension
        for ext in ('jpg', 'jpeg', 'png'):
            path = BANNERS_PATH / f'{filename}.{ext}'
            if path.exists():
                break
        else:
            # no file exists
            path = DEFAULT_BANNER
    else:
        # empty path or favicon, serve default banner
        path = DEFAULT_BANNER

    ext = 'png' if path.suffix == '.png' else 'jpeg'
    conn.add_resp_header(f'Content-Type: image/{ext}')
    return path.read_bytes()
Exemple #4
0
async def bancho_handler(conn: Connection) -> bytes:
    if 'User-Agent' not in conn.headers:
        return

    if conn.headers['User-Agent'] != 'osu!':
        # most likely a request from a browser.
        return b'<!DOCTYPE html>' + '<br>'.join((
            f'Running gulag v{glob.version}',
            f'Players online: {len(glob.players) - 1}',
            '<a href="https://github.com/cmyui/gulag">Source code</a>',
            '',
            '<b>Packets handled</b>',
            '<br>'.join(f'{p.name} ({p.value})' for p in glob.bancho_packets)
        )).encode()

    # check for 'osu-token' in the headers.
    # if it's not there, this is a login request.

    if 'osu-token' not in conn.headers:
        # login is a bit of a special case,
        # so we'll handle it separately.
        resp, token = await login(
            conn.body, conn.headers['X-Real-IP']
        )

        conn.add_resp_header(f'cho-token: {token}')
        return resp

    # get the player from the specified osu token.
    player = await glob.players.get(token=conn.headers['osu-token'])

    if not player:
        # token was not found; changes are, we just restarted
        # the server. just tell their client to re-connect.
        return packets.notification('Server is restarting') + \
               packets.restartServer(0) # send 0ms since server is up

    # bancho connections can be comprised of multiple packets;
    # our reader is designed to iterate through them individually,
    # allowing logic to be implemented around the actual handler.

    # NOTE: the reader will internally discard any
    # packets whose logic has not been defined.
    async for packet in BanchoPacketReader(conn.body):
        await packet.handle(player)

        if glob.config.debug:
            log(f'{packet.type!r}', Ansi.LMAGENTA)

    player.last_recv_time = time.time()

    # TODO: this could probably be done better?
    resp = bytearray()

    while not player.queue_empty():
        # read all queued packets into stream
        resp += player.dequeue()

    conn.add_resp_header('Content-Type: text/html; charset=UTF-8')
    resp = bytes(resp)

    # even if the packet is empty, we have to
    # send back an empty response so the client
    # knows it was successfully delivered.
    return resp
Exemple #5
0
async def everything(conn: Connection) -> Optional[bytes]:
    conn.resp_headers['Location'] = f'https://b.ppy.sh{conn.path}'
    return (301, b'')