Skip to content

Commit

Permalink
Callback API support
Browse files Browse the repository at this point in the history
  • Loading branch information
prostomarkeloff committed Apr 9, 2020
1 parent 26808fd commit bed9b1c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._aiohttp import AIOHTTPCallbackExtension
70 changes: 70 additions & 0 deletions vkwave/bots/core/dispatching/extensions/callback/_aiohttp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from vkwave.bots.core.dispatching.extensions.base import BaseExtension
from vkwave.bots.core.dispatching.events.raw import ExtensionEvent
from .conf import ConfirmationStorage
from vkwave.bots.core.tokens.types import GroupId
from vkwave.bots.core.types.bot_type import BotType
from vkwave.bots.core.dispatching.dp.processing_options import ProcessEventOptions

from aiohttp import web

from typing import Optional, TYPE_CHECKING
from asyncio import get_running_loop

if TYPE_CHECKING:
from vkwave.bots.core.dispatching.dp.dp import Dispatcher

class CallbackView(web.View):
async def get(self):
raise web.HTTPForbidden()

async def post(self):
event: dict = await self.request.json()
e_type = event.get("type")
if not e_type:
raise web.HTTPForbidden()
group_id = event["group_id"]

if e_type == "confirmation":
return web.Response(body = await self.request.app["storage"].get_confirmation(GroupId(group_id)))

if self.request.app["support_secret"]:
if not event["secret"] == self.request.app["secret"]:
raise web.HTTPForbidden()

options = ProcessEventOptions(do_not_handle=False)
revent = ExtensionEvent(BotType.BOT, event)

get_running_loop().create_task(self.request.app["dp"].process_event(revent, options))

return web.Response(body="ok")

class AIOHTTPCallbackExtension(BaseExtension):
def __init__(self, dp: "Dispatcher", path: str, host: str, port: int, secret: Optional[str] = None, confirmation_storage: Optional[ConfirmationStorage] = None):
self.confirmation_storage = confirmation_storage or ConfirmationStorage()
self.secret = secret # maybe we need secret storage too?
self.dp = dp

self.path = path
self.host = host
self.port = port

def add_confirmation(self, group_id: GroupId, confirmation: str):
self.confirmation_storage.add_confirmation(group_id, confirmation)

async def _start(self):
app = web.Application()
app["secret"] = self.secret
app["support_secret"] = bool(self.secret)
app["storage"] = self.confirmation_storage
app["dp"] = self.dp

app.router.add_view(self.path, CallbackView)

runner = web.AppRunner(app)
await runner.setup()

site = web.TCPSite(runner, self.host, self.port)
await site.start()

async def start(self):
get_running_loop().create_task(self._start())
28 changes: 28 additions & 0 deletions vkwave/bots/core/dispatching/extensions/callback/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from abc import ABC, abstractmethod
from vkwave.bots.core.tokens.types import GroupId
from typing import Dict

class AbstractGetConfirmationStrategy(ABC):
@abstractmethod
async def get_confirmation(self, group_id: GroupId) -> str:
...

class NotImplementedGetConfirmationStrategy(AbstractGetConfirmationStrategy):
async def get_confirmation(self, group_id: GroupId) -> str:
raise NotImplementedError

class ConfirmationStorage:
def __init__(self):
self.confirmations: Dict[GroupId, str] = {}
self.strategy: AbstractGetConfirmationStrategy = NotImplementedGetConfirmationStrategy()

def add_confirmation(self, group_id: GroupId, confirmation: str):
self.confirmations[group_id] = confirmation

async def get_confirmation(self, group_id: GroupId) -> str:
cached = self.confirmations.get(group_id)
if cached:
return cached
confirmation = await self.strategy.get_confirmation(group_id)
self.add_confirmation(group_id, confirmation)
return confirmation
9 changes: 6 additions & 3 deletions vkwave/bots/core/tokens/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ def _get_cached(self, id_to_check: T) -> Optional[AnyABCToken]:
return self.tokens.get(id_to_check)

async def get_token(self, id_to_check: T) -> AnyABCToken:
return self._get_cached(id_to_check) or (
await self.get_token_strategy.get_token(id_to_check)
)
cached = self._get_cached(id_to_check)
if cached:
return cached
token = await self.get_token_strategy.get_token(id_to_check)
self.tokens[id_to_check] = token
return token

0 comments on commit bed9b1c

Please sign in to comment.