def add_mod(request: Request, game: dict[str, Any], version: dict[str, Any]):
    if request.POST:
        if not request.POST.get('id', True):
            DB.execute('INSERT INTO Mods (game, name, description, created, image) VALUES (?, ?, ?, ?, ?)', (game['id'], request.POST['name'], request.POST['description'], request.POST['created'], list(request.FILES['icon'].values())[0].read()))
            request.POST['id'] = DB.execute('SELECT last_insert_rowid() as row').fetchone()['row']
        DB.execute('INSERT INTO ModVersions (mod, version, game_version, released) VALUES (?, ?, ?, ?)', (request.POST['id'], request.POST['version'], version['id'], request.POST['released']))
        DB.commit()
        return '', 307, {'Location': f'/{game["name"]}/mods/{request.POST["name"]}/{request.POST["version"]}/'}
    return render(request, 'html/add_mod.html', {'game': game, 'version': version, 'mods': DB.execute('SELECT name, created, id FROM Mods WHERE game=? AND id NOT IN (SELECT mod FROM ModVersions WHERE game_version=?) ORDER BY name', (game['id'], version['id'])).fetchall()})
def add_item(request: Request, game: dict[str, Any], version: dict[str, Any]):
    if request.POST:
        if not request.POST.get('id', True):
            DB.execute('INSERT INTO GameItems (name, image) VALUES (?, ?)', (request.POST['name'], list(request.FILES['icon'].values())[0].read()))
            request.POST['id'] = DB.execute('SELECT last_insert_rowid() as row').fetchone()['row']
        DB.execute('INSERT INTO GameVersionItemMap VALUES (?, ?)', (version['id'], request.POST['id']))
        DB.commit()
        return '', 307, {'Location': f'/{game["name"]}/{version["version"]}/items/{request.POST["name"]}/'}
    return render(request, 'html/add_item.html', {'game': game, 'version': version, 'items': DB.execute('SELECT name, GameItems.id FROM GameItems INNER JOIN GameVersionItemMap GVIM ON GameItems.id = GVIM.item INNER JOIN GameVersions GV ON GV.id = GVIM.version WHERE game=? AND GameItems.id NOT IN (SELECT item FROM GameVersionItemMap WHERE version=?) ORDER BY name', (game['id'], version['id'])).fetchall()})
示例#3
0
 def error_output(self, environ: dict, start_response: Callable) -> List[bytes]:
     """Override to email ADMINS or send debug page."""
     if environ:
         environ = Request(environ)
     er = ExceptionReporter(environ, *sys.exc_info()).get_traceback_html()[0]
     if App._admins and not App.debug and Mail.default_email['host']:
         Mail(f'Internal Server Error: {(environ or {}).get("PATH_INFO", "???")}', '\n'.join(str(e) for e in sys.exc_info()), App._admins, html=er.decode()).embed().send()
     start_response(self.error_status, self.error_headers[:] if not App.debug else [('Content-Type', 'text/html')], sys.exc_info())
     return [er] if App.debug else [self.error_body]
示例#4
0
 def wrapped(*args, **kwargs):
     request = kwargs.get(
         'request', args[0] if args else Request()
     )  # get request args otherwise use blank data (only gets correct args when doing "@route() \n @auth" otherwise "@auth \n @route()" it will not have the request argument
     if 'auth' not in request.COOKIE or request.COOKIE[
             'auth'].value not in set():
         return '', 303, {
             'Location': f'/login/?next={request.PATH_INFO}'
         }  # should change /login/?next= to the url of login for you application
     return f(*args, **kwargs)
示例#5
0
 def setup_env(cls, port: int):
     if not cls.base_environ:
         cls.base_environ = Request({
             'SERVER_NAME': socket.gethostname(),
             'GATEWAY_INTERFACE': 'CGI/1.1',
             'SERVER_PORT': str(port),
             'REMOTE_HOST': '',
             'CONTENT_LENGTH': '',
             'SCRIPT_NAME': ''
         })
示例#6
0
 def __call__(self, env: dict, start_response: Callable):
     path = env['PATH_INFO']
     f = self._handle_route_cache(path)
     env = Request(env)
     headers = {}
     cookie = set(env['COOKIE'].output().replace('\r', '').split('\n'))
     called = False
     try:
         if isinstance(f, bool):
             result = self.error_routes.get(
                 404, (lambda e: (b'', 404, {
                     'Content-Type': 'text/public'
                 })))(env)
         if path[-1:] != '/' and 'result' not in locals() and not f[
                 0].no_end_slash:  # auto rediects to url that ends in / if no_end_slash is False
             result = self.error_routes.get(307, (lambda e, *a, **k:
                                                  (b'', 307, {
                                                      'Location': f'{path}/'
                                                  })))(env, *f[1], **f[2])
         if 'result' not in locals():
             r = self._handle_cors(f, headers, env)
             if ('*' not in f[0].methods
                     and env['REQUEST_METHOD'].lower() not in f[0].methods
                 ) or not r:  # checks for allowed methods
                 result = self.error_routes.get(
                     405, (lambda e, *a, **k: (b'', 405, {
                         'Content-Type': 'text/public'
                     })))(env, *f[1], **f[2])
             else:
                 result = f[0](env, *f[1], **f[2])
                 called = True
     except Exception:
         result = self.error_routes[500](env, *f[1], **f[2])
     r = self._handle_result(result, headers, cookie, env)
     status = int(r[1].split()[0])
     if called and status in self.error_routes and status not in f[
             0].disable_default_errors:
         r = self._handle_result(
             self.error_routes[status](env, *f[1], **f[2]), headers, cookie,
             env)
     start_response(*r[1:])
     return r[0]
示例#7
0
 def get_environ(self) -> Request:
     """Read headers / body and generate Request object.
     :returns:Request"""
     env = Request({'SERVER_PROTOCOL': self.request_version, 'SERVER_SOFTWARE': self.server_version, 'REQUEST_METHOD': self.command.upper(), 'BODY': b'', 'GET': {}, 'POST': {}, 'PATCH': {}, 'PUT': {}, 'OPTIONS': {}, 'DELETE': {}, 'FILES': {}, 'COOKIE': SimpleCookie(self.headers.get('COOKIE')), 'HEADERS': dict(self.headers), 'REMOTE_ADDR': self.client_address[0], 'CONTENT_TYPE': self.headers.get_content_type(), 'HOST': self.headers['HOST']})
     env['HEADERS'] = {k.upper().strip(): v for k, v in env['HEADERS'].items()}
     path, env['QUERY_STRING'] = self.path.split('?', 1) if '?' in self.path else (self.path, '')
     env['PATH_INFO'] = unquote_plus(path, 'iso-8859-1')
     host = env['HEADERS'].get('X-REAL-IP') or env['HEADERS'].get('X-FORWARDED-FOR', '').split(',')[-1].strip() or self.address_string()
     if host != self.client_address[0]:
         env['REMOTE_HOST'] = host
         self.client_address = (host, self.client_address[1])
     env['CONTENT_LENGTH'] = int(self.headers.get('content-length', '0'))
     if len(env['BODY']) != env['CONTENT_LENGTH']:
         env['BODY'] += self.rfile.read(env['CONTENT_LENGTH'] - len(env['BODY']))
     boundary = re.findall(r'boundary=-*([\w]+)', self.headers.get('content-type', ''))  # boundary is used to catch multipart form data (includes file uploads)
     content_type = env['CONTENT_TYPE'].lower()
     if boundary:
         self._get_boundary_enclosed(boundary, env)
     elif content_type == 'application/json' and env['BODY']:
         env[env['REQUEST_METHOD']] = json.loads(env['BODY'])
     elif content_type == 'application/x-www-form-urlencoded':
         env[env['REQUEST_METHOD']] = self._parse_qs(env['BODY'].decode())
     elif content_type == 'multipart/form-data':
         for q in re.sub(r'-{15,}\d+', '+@~!@+', env['BODY'].decode().replace('\n', '')).split('+@~!@+'):
             if '=' in q:
                 q = q.split(';')[1].strip().split('=', 1)[1].replace('"', '').split('\r\r')
                 k, v = [unquote_plus(a) if a else a for a in q]
                 v = v.replace('\r', '')
                 request_method = env[env['REQUEST_METHOD']]
                 if k in request_method:
                     try:
                         request_method[k].append(v)
                     except AttributeError:
                         request_method[k] = [request_method[k], v]
                 else:
                     request_method[k] = v
     if env['QUERY_STRING']:
         env['GET'] = self._parse_qs(env['QUERY_STRING'])
     return env
示例#8
0
 def __call__(self, env: dict, start_response: Callable):
     path = env['PATH_INFO']
     env = Request(env)
     f_list = self._handle_route_cache(env)
     headers = {}
     cookie = set(env['COOKIE'].output().replace('\r', '').split('\n'))
     called = False
     try:
         if not f_list:
             result = self.error_routes.get(404, (lambda e: (b'', 404, {'Content-Type': 'text/public'})))(env)
         for f in f_list:
             if path[-1:] != '/' and 'result' not in locals() and not f[0].no_end_slash:  # auto rediects to url that ends in / if no_end_slash is False
                 result = self.error_routes.get(307, (lambda e, *a, **k: (b'', 307, {'Location': f'{path}/'})))(env, *f[1], **f[2])
             else:
                 r = self._handle_cors(f, headers, env)
                 if ('*' not in f[0].methods and env['REQUEST_METHOD'].lower() not in f[0].methods) or not r:  # checks for allowed methods
                     result = self.error_routes.get(405, (lambda e, *a, **k: (b'', 405, {'Content-Type': 'text/public'})))(env, *f[1], **f[2])
                 else:
                     result = f[0](env, *f[1], **f[2])
                     called = True
             l_result = len(result or [])
             if l_result <= 1 or l_result > 3 or isinstance(result, dict) or (l_result >= 2 and result[1] != 405):
                 break
     except ResponseError as e:
         if e.code in self.error_routes and e.code not in f[0].disable_default_errors:
             result = self.error_routes[e.code](env, *f[1], **f[2])
         else:
             if e.message is None:
                 result = b'', e.code, {'Content-Type': 'text/public'}
             else:
                 result = e.message, e.code, None
     except Exception as e:
         result = self.error_routes[500](env, *f[1], **f[2])
     r = self._handle_result(result, headers, cookie, env)
     status = int(r[1].split()[0])
     if called and status in self.error_routes and status not in f[0].disable_default_errors:
         r = self._handle_result(self.error_routes[status](env, *f[1], **f[2]), headers, cookie, env)
     start_response(*r[1:])
     return r[0]
示例#9
0
class WebServer(ThreadingTCPServer):
    request_queue_size = 500
    allow_reuse_address = True
    application = None
    base_environ = Request()
    daemon_threads = True
    clients, handlers = {}, {}  # websocket vars
    id_counter = 0
    websocket_handlers = {'new': {}, 'message': {}, 'left': {}}

    def __init__(self, server_address, request_handler_class, bind_and_activate: bool = True):
        super().__init__(server_address, request_handler_class, bind_and_activate)

    def server_bind(self):
        """Override server_bind to store the server name."""
        super().server_bind()
        self.setup_env(self.server_address[1])

    @classmethod
    def attach_websocket_handler(cls, type: str, function: Callable[[dict, 'WebServer', Optional[str]], None], path: Optional[str] = None):
        if type not in {'new', 'message', 'left'}:
            raise ValueError
        try:
            cls.websocket_handlers[type][path].append(function)
        except KeyError:
            cls.websocket_handlers[type][path] = [function]

    @classmethod
    def setup_env(cls, port: int):
        if not cls.base_environ:
            cls.base_environ = Request({'SERVER_NAME': socket.gethostname(), 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': str(port), 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': ''})

    def message_received(self, handler: 'RequestHandler', msg: str):
        self.handle(self.handlers[id(handler)], 'message', msg)

    def new_client(self, handler: 'RequestHandler', env: Request):
        self.id_counter += 1
        client = {
            'id': self.id_counter,
            'handler': handler,
            'request': env,
            'handler_id': id(handler)
        }
        self.handlers[client['handler_id']] = self.clients[client['id']] = client
        self.handle(client, 'new')

    def client_left(self, handler: 'RequestHandler'):
        try:
            client = self.handlers[id(handler)]
            self.handle(client, 'left')
            del self.clients[client['id']]
            del self.handlers[client['handler_id']]
        except KeyError:
            pass
        for client in list(self.clients.values()):
            if client['handler'].connection._closed:
                del self.clients[client['id']]
                del self.handlers[client['handler_id']]
        for client in list(self.handlers.values()):
            if client['handler'].connection._closed:
                del self.clients[client['id']]
                del self.handlers[client['handler_id']]

    def handle(self, client: dict, type: str, msg: Optional[str] = None):
        for path, channels in self.websocket_handlers[type].items():
            if not path or re.fullmatch(path, client['request'].PATH_INFO):
                for channel in channels:
                    channel(client, self, *([msg] if msg is not None else []))

    @staticmethod
    def send_message(client: dict, msg: Union[str, bytes]):
        client['handler'].send_message(msg)

    @staticmethod
    def send_json(client: dict, obj):
        client['handler'].send_json(obj)

    def send_message_all(self, msg: Union[str, bytes]):
        for client in self.clients.values():
            client['handler'].send_message(msg)

    def send_json_all(self, obj):
        for client in self.clients.values():
            client['handler'].send_json(obj)

    def serve(self):
        print(f'Server Started on {self.server_address}')
        try:
            self.serve_forever(.1)
        except KeyboardInterrupt:
            self.shutdown()