Source code for ReFreSH.MobileSuit.SuitHost
import asyncio
from typing import List
from .Core.ISuitMiddleware import ISuitMiddleware, SuitRequestDelegate
from .Core.Services.SuitExceptionHandler import ISuitExceptionHandler
from .Core.Services.TaskService import TaskRecorder
from .Core.SuitContext import SuitContext
from .RequestStatus import RequestStatus
from ..DependencyInjection import ServiceProvider
[docs]
class SuitHost:
"""A entity, which serves the shell functions of a mobile-suit program."""
def __init__(self, services: ServiceProvider, middleware: List[ISuitMiddleware], cancellationTasks: TaskRecorder):
self.Services = services
self._suitApp = middleware
self._cancellationTasks = cancellationTasks
self._exceptionHandler = services.GetRequiredService(ISuitExceptionHandler)
self._rootScope = services
self._hostTask = None
[docs]
@staticmethod
def CreateMiddlewareInvocation(m: ISuitMiddleware, nxt: SuitRequestDelegate) -> SuitRequestDelegate:
async def invocation(context: SuitContext):
await m.InvokeAsync(context, nxt)
return invocation
[docs]
@staticmethod
async def EmptyMiddlewareInvocation(c: SuitContext):
pass
[docs]
def Start(self):
if self._hostTask is not None:
return
requestStack = [SuitHost.EmptyMiddlewareInvocation]
for middleware in reversed(self._suitApp):
nextStep = requestStack[-1]
requestStack.append(SuitHost.CreateMiddlewareInvocation(middleware, nextStep))
handleRequest = requestStack[-1]
# TODO: startup arg support
# appInfo = self._rootScope.GetRequiredService(ISuitAppInfo)
# if appInfo.StartArgs:
# requestScope = self.Services.CreateScope()
# context = SuitContext(requestScope)
# context.RequestStatus = RequestStatus.NotHandled
# context.Request = appInfo.StartArgs
#
# try:
# await handleRequest(context)
# except Exception as ex:
# context.Exception = ex
# context.RequestStatus = RequestStatus.Faulted
# await self._exceptionHandler.InvokeAsync(context)
self._hostTask = asyncio.create_task(self.HandleRequest(handleRequest))
[docs]
def Stop(self):
if self._hostTask is None:
return
self._hostTask.cancel()
self._rootScope.Dispose()
self._hostTask = None
[docs]
async def HandleRequest(self, requestHandler: SuitRequestDelegate):
while True:
requestScope = self.Services.CreateScope()
context = SuitContext(requestScope)
# TODO: cancel key
# cancelKeyHandler = SuitHost.CreateCancelKeyHandler(context)
try:
await requestHandler(context)
except Exception as ex:
context.Exception = ex
context.RequestStatus = RequestStatus.Faulted
await self._exceptionHandler.InvokeAsync(context)
continue
if context.RequestStatus == RequestStatus.OnExit:
break
# TODO: cancel key
# @staticmethod
# def CreateCancelKeyHandler(context: SuitContext):
# def cancelKeyHandler(sender, e):
# e.Cancel = True
# context.CancellationToken.cancel()
#
# return cancelKeyHandler
[docs]
def Dispose(self):
self._rootScope.Dispose()
[docs]
async def RunAsync(self):
self.Start()
await self._hostTask
[docs]
def Run(self):
asyncio.run(self.RunAsync())