コード例 #1
0
ファイル: web.py プロジェクト: grammy-jiang/Bifrost
class Web(BaseComponent, LoggerMixin):
    """
    Web Extension
    """

    name = "Web"
    setting_prefix = "WEB_"

    def __init__(self, service, name: str = None, setting_prefix: str = None):
        """

        :param service:
        :type service:
        :param name:
        :type name: str
        :param setting_prefix:
        :type setting_prefix: str
        """
        super(Web, self).__init__(service, name, setting_prefix)

        self.app = Sanic(self.name)
        self.app.config["SERVICE"] = self.service

        # configure normal route
        self.app.add_route(self.home, "/")

        self.server = None  # type: ignore

    async def start(self) -> None:
        """
        start this extension
        :return:
        :rtype: None
        """
        ssl_context: Optional[ssl.SSLContext]
        if self.config["SSL_CERT_FILE"]:
            ssl_context = ssl.create_default_context(
                purpose=ssl.Purpose.CLIENT_AUTH)
            ssl_context.load_cert_chain(
                certfile=self.config["SSL_CERT_FILE"],
                keyfile=self.config["SSL_KEY_FILE"],
                password=self.config["SSL_PASSWORD"],
            )
        else:
            ssl_context = None

        self.server = await self.app.create_server(
            host=self.config["ADDRESS"],
            port=self.config["PORT"],
            debug=self.config["DEBUG"],
            ssl=ssl_context,
            return_asyncio_server=True,
        )
        self.logger.info("Extension [%s] is running...", self.name)

    async def stop(self) -> None:
        """
        stop this extension
        :return:
        :rtype: None
        """
        if self.server:
            self.server.close()
            self.logger.info("Extension [%s] is stopped.", self.name)

    async def home(  # pylint: disable=unused-argument
            self, request: Request) -> HTTPResponse:
        """

        :param request:
        :type request: Request
        :return:
        :rtype: HTTPResponse
        """
        return json({"hello": "world"})
コード例 #2
0
class TestSanic(unittest.TestCase):
    app = None

    def setUp(self):
        modules.flags_manager.remove_all_flags()

        self.app = Sanic()
        self.app.add_route(test_api, '/test', methods=['POST'])

        init_sanic('test_app', self.app, setup_kuber_config_loader=False)

        flags.DEFINE_INTEGER_FLAG("test")
        self.loader = KuberConfigLoader("test_service")
        self.loader.load_config(
            config_pb2.GlobalConfig(
                flags=[{
                    "name": "test",
                    "type": "INTEGER",
                    "value": {
                        "base_value": {
                            "number_value": 1
                        }
                    }
                }],
                experiments={
                    2:
                    ExperimentDefinition(
                        id=2,
                        flag_values={
                            "test": FlagValue(base_value={"number_value": 2})
                        })
                }))
        self.server = Process(target=self.app.run, args=("127.0.0.1", 8008))
        self.server.start()
        sleep(1)

    def tearDown(self):
        self.server.terminate()

    def test_experiments(self):
        headers = {
            'x-internal-state-bin': 'EgA='  # experiments: []
        }
        data = requests.post(url='http://127.0.0.1:8008/test',
                             headers=headers).json()
        self.assertEqual(data['test'], 1)

        headers = {
            'x-internal-state-bin': 'EgEC'  # experiments: [2]
        }
        data = requests.post(url='http://127.0.0.1:8008/test',
                             headers=headers).json()
        self.assertEqual(data['test'], 2)

    def test_trace_info(self):
        headers = {
            'x-internal-trace-info-bin':
            'ChYSCzA5MTIzNDU2Nzg5CgcxLjIuMy40'  # ip: 1.2.3.4, phone: 09123456789
        }
        data = requests.post(url='http://127.0.0.1:8008/test',
                             headers=headers).json()
        self.assertEqual(data['trace_info']['client']['ip'], '1.2.3.4')
        self.assertEqual(data['trace_info']['client']['phone'], '09123456789')
コード例 #3
0
class Hiyobot:
    commands: dict[str, RegisterdInfo] = {}
    compoents: dict[str, Component] = {}

    def __init__(
        self,
        client_public_key: str,
        token: str,
        uri: str = "discord_interaction",
        production: bool = False,
    ) -> None:
        self.sanic = Sanic("hiyobot")
        self.uri = uri
        self.token = token
        self.client_public_key = client_public_key

        self.__setup()

    def __setup(self):
        self.sanic.add_route(self.__handler, self.uri, ["POST"])

        # Injection
        self.sanic.ctx.http = DiscordBaseHTTP(self.token)
        self.sanic.ctx.mintchoco = Mintchoco()
        self.sanic.ctx.handler = self
        self.sanic.ctx.request = BaseHTTP()

    def command_register(self, info: RegisterCommand):
        self.commands.update({info.registerd_info.name: info.registerd_info})

    def component_register(self, component: Component):
        for k in component.mapping.keys():
            self.compoents[k] = component

        if not component.start_check_timeout:
            create_task(component.timeout_manager(self))

    @staticmethod
    def verify_signiture(
        raw_body: bytes, signature: str, timestamp: str, client_public_key: str
    ):
        message = timestamp.encode() + raw_body
        try:
            vk = VerifyKey(bytes.fromhex(client_public_key))
            vk.verify(message, bytes.fromhex(signature))  # type: ignore
            return True
        except BadSignatureError:
            return False

    async def __handler(self, request: HiyobotRequest):
        request.ctx.response = Response(request)
        request.ctx.interaction = Interaction(request.json)
        signature = request.headers.get("X-Signature-Ed25519")
        timestamp = request.headers.get("X-Signature-Timestamp")
        if (
            signature
            and timestamp
            and self.verify_signiture(
                request.body, signature, timestamp, self.client_public_key
            )
        ):
            if request.json["type"] == 1:
                return json({"type": 1})

            if request.json["type"] == 2:
                return await self.dispatch_application_command(request)

            if request.json["type"] == 3:
                return await self.dispatch_message_component(request)

        raise Unauthorized("not_verified", 401)

    async def dispatch_application_command(self, request: HiyobotRequest):
        if request.ctx.interaction.data:
            interaction_data = cast(
                ApplicationCommandInteractionData, request.ctx.interaction.data
            )

            if interaction_data.get("type") == 1:
                if interaction_data["name"] in self.commands:
                    command = self.commands[interaction_data["name"]]
                    if interaction_options := interaction_data.get("options"):
                        option = interaction_options[0]
                        # Handle Subcommand
                        if option["type"] == 1:
                            if option["name"] in command.sub_command:
                                sub_command_func = command.sub_command[option["name"]]
                                await sub_command_func(
                                    request,
                                    *tuple(map(lambda x: x["value"], option["options"])),  # type: ignore
                                )
                        # Handle Single Command
                        else:
                            if interaction_data["name"] in command.single_command:
                                single_command_func = command.single_command[
                                    interaction_data["name"]
                                ]
                                await single_command_func(
                                    request,
                                    *tuple(
                                        map(lambda x: x["value"], option["options"])  # type: ignore
                                    ),
                                )