2022-01-10 00:00:14 +08:00
|
|
|
import json
|
2021-09-20 17:27:40 +08:00
|
|
|
import logging
|
|
|
|
from typing import List
|
2021-09-20 18:50:01 +08:00
|
|
|
|
2022-11-06 20:09:44 +08:00
|
|
|
from fastapi import FastAPI, Request, WebSocket
|
2022-01-19 08:40:02 +08:00
|
|
|
from fastapi.staticfiles import StaticFiles
|
2023-03-19 23:21:32 +08:00
|
|
|
from starlette.concurrency import run_until_first_complete
|
|
|
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
|
|
|
from starlette.middleware.cors import CORSMiddleware
|
|
|
|
from strawberry.asgi import GraphQL
|
|
|
|
from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
|
2023-04-08 14:41:48 +08:00
|
|
|
#
|
|
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from fastapi.templating import Jinja2Templates
|
|
|
|
from fastapi.responses import HTMLResponse
|
2023-03-19 23:21:32 +08:00
|
|
|
|
2022-11-06 20:09:44 +08:00
|
|
|
from felicity.api.gql.schema import gql_schema # noqa
|
2022-01-19 08:40:02 +08:00
|
|
|
from felicity.api.rest.api_v1.api import api_router # noqa
|
|
|
|
from felicity.apps.common.channel import broadcast
|
2023-03-19 23:21:32 +08:00
|
|
|
from felicity.apps.job.sched import felicity_halt_workforce, felicity_workforce_init
|
2022-11-06 20:09:44 +08:00
|
|
|
from felicity.apps.notification.utils import FelicityNotifier, FelicityStreamer
|
2022-01-19 08:40:02 +08:00
|
|
|
from felicity.core.config import settings # noqa
|
|
|
|
from felicity.core.repeater import repeat_every
|
|
|
|
from felicity.init import initialize_felicity # noqa
|
2022-11-06 18:42:33 +08:00
|
|
|
from felicity.middlewares.auth_backend import FelicityAuthBackend
|
2022-11-06 20:09:44 +08:00
|
|
|
from felicity.utils.dirs import resolve_root_dirs
|
2022-11-07 15:20:01 +08:00
|
|
|
from felicity.utils.email.email import send_new_account_email
|
2023-04-08 14:48:01 +08:00
|
|
|
from felicity.views import setup_backends
|
2022-01-19 08:40:02 +08:00
|
|
|
|
2021-09-20 17:27:40 +08:00
|
|
|
|
2022-11-06 18:42:33 +08:00
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
logger = logging.getLogger(__name__)
|
2021-09-20 17:27:40 +08:00
|
|
|
|
2023-04-08 14:41:48 +08:00
|
|
|
|
2021-09-20 17:27:40 +08:00
|
|
|
flims = FastAPI(
|
2022-01-10 00:00:14 +08:00
|
|
|
title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json"
|
2021-09-20 17:27:40 +08:00
|
|
|
)
|
|
|
|
|
2023-02-24 08:44:14 +08:00
|
|
|
|
2021-09-20 17:27:40 +08:00
|
|
|
@flims.on_event("startup")
|
|
|
|
async def startup():
|
2021-12-17 04:26:13 +08:00
|
|
|
# print("\n")
|
|
|
|
# print(pf.Figlet("doom").renderText("FELICITY LIMS")) # "puffy"
|
2022-02-23 18:35:43 +08:00
|
|
|
if settings.LOAD_SETUP_DATA:
|
|
|
|
await initialize_felicity()
|
|
|
|
|
2021-09-20 17:27:40 +08:00
|
|
|
felicity_workforce_init()
|
|
|
|
|
2021-11-23 05:49:10 +08:00
|
|
|
|
2021-10-07 15:17:20 +08:00
|
|
|
@flims.on_event("startup")
|
|
|
|
@repeat_every(seconds=3) # 60 * 60 = 1 hour
|
|
|
|
async def always_and_forever():
|
2021-10-12 11:36:53 +08:00
|
|
|
# print(datetime.now())
|
|
|
|
pass
|
2021-09-20 17:27:40 +08:00
|
|
|
|
2021-11-23 05:49:10 +08:00
|
|
|
|
2021-09-20 17:27:40 +08:00
|
|
|
@flims.on_event("shutdown")
|
|
|
|
async def shutdown():
|
|
|
|
felicity_halt_workforce()
|
|
|
|
|
|
|
|
|
|
|
|
# Set all CORS enabled origins
|
|
|
|
if settings.BACKEND_CORS_ORIGINS:
|
|
|
|
flims.add_middleware(
|
|
|
|
CORSMiddleware,
|
2023-04-08 14:41:48 +08:00
|
|
|
allow_origins=[str(origin)
|
|
|
|
for origin in settings.BACKEND_CORS_ORIGINS],
|
2021-09-20 17:27:40 +08:00
|
|
|
allow_credentials=True,
|
|
|
|
allow_methods=["*"],
|
|
|
|
allow_headers=["*"],
|
2021-01-06 19:52:14 +08:00
|
|
|
)
|
|
|
|
|
2022-01-10 00:00:14 +08:00
|
|
|
flims.add_middleware(AuthenticationMiddleware, backend=FelicityAuthBackend())
|
2021-09-20 17:27:40 +08:00
|
|
|
|
2022-11-06 20:09:44 +08:00
|
|
|
|
2022-03-24 14:59:39 +08:00
|
|
|
@flims.middleware("http")
|
|
|
|
async def set_custom_attr(request: Request, call_next):
|
|
|
|
request.state.notifier = FelicityNotifier()
|
|
|
|
request.state.streamer = FelicityStreamer()
|
|
|
|
response = await call_next(request)
|
|
|
|
return response
|
|
|
|
|
2022-11-06 20:09:44 +08:00
|
|
|
|
2022-01-10 00:00:14 +08:00
|
|
|
graphql_app = GraphQL(
|
|
|
|
gql_schema,
|
2023-04-08 14:41:48 +08:00
|
|
|
subscription_protocols=[GRAPHQL_WS_PROTOCOL,
|
|
|
|
GRAPHQL_TRANSPORT_WS_PROTOCOL],
|
2022-01-10 00:00:14 +08:00
|
|
|
)
|
2021-09-20 18:50:01 +08:00
|
|
|
|
2023-04-08 14:48:01 +08:00
|
|
|
setup_backends(flims, settings.SERVE_WEBAPP)
|
2021-09-20 17:27:40 +08:00
|
|
|
flims.include_router(api_router, prefix=settings.API_V1_STR)
|
2021-09-20 18:50:01 +08:00
|
|
|
flims.add_route("/felicity-gql", graphql_app)
|
2023-04-08 14:41:48 +08:00
|
|
|
flims.add_websocket_route("/felicity-gql", graphql_app,
|
|
|
|
"felicity-subscriptions")
|
2022-01-19 08:40:02 +08:00
|
|
|
resolve_root_dirs()
|
2022-11-06 20:09:44 +08:00
|
|
|
flims.mount("/media", StaticFiles(directory="media"), name="media")
|
2023-04-08 15:07:19 +08:00
|
|
|
|
2023-04-08 14:41:48 +08:00
|
|
|
|
2023-04-08 14:48:01 +08:00
|
|
|
if settings.SERVE_WEBAPP:
|
|
|
|
templates = Jinja2Templates(directory=settings.STATIC_DIR)
|
2023-04-08 14:41:48 +08:00
|
|
|
|
2023-04-08 15:07:19 +08:00
|
|
|
flims.mount(
|
2023-04-08 15:08:48 +08:00
|
|
|
"/assets", StaticFiles(directory=settings.STATIC_DIR + "/assets", html=True), name="assets"
|
2023-04-08 15:07:19 +08:00
|
|
|
)
|
|
|
|
|
2023-04-08 14:48:01 +08:00
|
|
|
@flims.get("/", response_class=HTMLResponse)
|
|
|
|
async def index_path(request: Request):
|
|
|
|
return templates.TemplateResponse("index.html", {"request": request})
|
2023-04-08 14:41:48 +08:00
|
|
|
|
2023-04-08 14:48:01 +08:00
|
|
|
@flims.get("/{catchall:path}", response_class=HTMLResponse)
|
|
|
|
async def index_path(request: Request):
|
|
|
|
return templates.TemplateResponse("index.html", {"request": request})
|
2022-01-19 08:40:02 +08:00
|
|
|
|
2021-12-16 20:19:08 +08:00
|
|
|
|
|
|
|
class ConnectionManager:
|
|
|
|
def __init__(self):
|
|
|
|
self.connections: List[WebSocket] = []
|
|
|
|
|
|
|
|
async def connect(self, websocket: WebSocket):
|
|
|
|
await websocket.accept()
|
|
|
|
self.connections.append(websocket)
|
|
|
|
|
|
|
|
async def broadcast(self, data: str):
|
|
|
|
for connection in self.connections:
|
|
|
|
await connection.send_text(data)
|
|
|
|
|
|
|
|
|
|
|
|
manager = ConnectionManager()
|
|
|
|
|
|
|
|
|
2023-04-08 14:41:48 +08:00
|
|
|
@ flims.websocket("/ws/{after_uid}")
|
2021-12-16 20:19:08 +08:00
|
|
|
async def websocket_endpoint(websocket: WebSocket, after_uid: int):
|
|
|
|
await manager.connect(websocket)
|
|
|
|
while True:
|
|
|
|
data = await websocket.receive_text()
|
|
|
|
await manager.broadcast(f"Client {after_uid}: {data}")
|
|
|
|
|
|
|
|
|
|
|
|
async def chatroom_ws(websocket):
|
|
|
|
await websocket.accept()
|
|
|
|
await run_until_first_complete(
|
|
|
|
(chatroom_ws_receiver, {"websocket": websocket}),
|
|
|
|
(chatroom_ws_sender, {"websocket": websocket}),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def chatroom_ws_receiver(websocket):
|
|
|
|
async for message in websocket.iter_text():
|
|
|
|
await broadcast.publish(channel="activities", message=message)
|
|
|
|
|
|
|
|
|
|
|
|
async def chatroom_ws_sender(websocket):
|
|
|
|
async with broadcast.subscribe(channel="activities") as subscriber:
|
|
|
|
async for event in subscriber:
|
|
|
|
await websocket.send_text(event.message)
|
|
|
|
|
|
|
|
|
|
|
|
flims.add_websocket_route("/chatter", chatroom_ws, "chatroom_ws")
|
|
|
|
|
|
|
|
|
|
|
|
async def get_streams(websocket):
|
|
|
|
async with broadcast.subscribe(channel="activities") as subscriber:
|
|
|
|
async for event in subscriber:
|
2022-01-10 00:00:14 +08:00
|
|
|
data = json.loads(
|
|
|
|
json.dumps(
|
|
|
|
event.message.marshal_simple(),
|
|
|
|
indent=4,
|
|
|
|
sort_keys=True,
|
|
|
|
default=str,
|
|
|
|
)
|
|
|
|
)
|
2021-12-16 20:19:08 +08:00
|
|
|
await websocket.send_json(data)
|
|
|
|
|
|
|
|
|
|
|
|
async def stream_socket(websocket):
|
|
|
|
await websocket.accept()
|
2022-01-10 00:00:14 +08:00
|
|
|
await run_until_first_complete((get_streams, {"websocket": websocket}))
|
2021-12-16 20:19:08 +08:00
|
|
|
|
|
|
|
|
2022-01-13 05:06:57 +08:00
|
|
|
flims.add_websocket_route("/streamer", stream_socket, "notification-only")
|