Skip to content

Commit

Permalink
🎉♻️💥🚧Integrated carefree-core
Browse files Browse the repository at this point in the history
  • Loading branch information
carefree0910 committed Jun 18, 2024
1 parent 409e690 commit e337f79
Show file tree
Hide file tree
Showing 49 changed files with 6,814 additions and 138 deletions.
18 changes: 7 additions & 11 deletions cfdraw/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
from aiohttp import ClientSession
from fastapi import FastAPI
from contextlib import asynccontextmanager
from cftool.misc import print_info
from cftool.misc import random_hash
from fastapi.middleware import cors

from cfdraw import constants
from cfdraw.utils import console
from cfdraw.config import get_config
from cfdraw.app.schema import IApp
from cfdraw.app.endpoints import *
from cfdraw.core.toolkit import console
from cfdraw.schema.plugins import IPlugin
from cfdraw.plugins.factory import Plugins
from cfdraw.plugins.factory import PluginFactory
from cfdraw.core.toolkit.misc import random_hash


async def ping() -> str:
Expand All @@ -31,11 +30,8 @@ def __init__(self, notification: Optional[str] = None) -> None:
async def lifespan(api: FastAPI) -> AsyncGenerator:
# startup

def info(msg: str) -> None:
print_info(msg)

info(f"🚀 Starting Backend Server at {self.config.api_url} ...")
info("🔨 Compiling Plugins & Endpoints...")
console.log(f"🚀 Starting Backend Server at {self.config.api_url} ...")
console.log("🔨 Compiling Plugins & Endpoints...")
tplugin_with_notification: List[Type[IPlugin]] = []
for tplugin in self.plugins.values():
tplugin.hash = self.hash
Expand All @@ -44,7 +40,7 @@ def info(msg: str) -> None:
tplugin_with_notification.append(tplugin)
if tplugin_with_notification or notification is not None:
console.rule("")
info(f"📣 Notifications:")
console.log(f"📣 Notifications:")
if notification is not None:
console.rule(f"[bold green][ GLOBAL ]")
console.print(notification)
Expand All @@ -56,8 +52,8 @@ def info(msg: str) -> None:
for endpoint in self.endpoints:
await endpoint.on_startup()
upload_root_path = self.config.upload_root_path
info(f"🔔 Your files will be saved to '{upload_root_path}'")
info("🎉 Backend Server is Ready!")
console.log(f"🔔 Your files will be saved to '{upload_root_path}'")
console.log("🎉 Backend Server is Ready!")

yield

Expand Down
6 changes: 3 additions & 3 deletions cfdraw/app/endpoints/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
from typing import Any
from typing import List
from pydantic import BaseModel
from cftool.web import raise_err
from cftool.web import get_responses
from cftool.misc import get_err_msg

from cfdraw.parsers import noli
from cfdraw.core.toolkit.web import raise_err
from cfdraw.core.toolkit.web import get_responses
from cfdraw.core.toolkit.misc import get_err_msg
from cfdraw.app.endpoints.base import IEndpoint


Expand Down
105 changes: 94 additions & 11 deletions cfdraw/app/endpoints/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,109 @@
import logging

from typing import Dict
from typing import List
from typing import Tuple
from typing import Generic
from typing import Iterator
from typing import Optional
from cftool.misc import get_err_msg
from cftool.misc import print_error
from cftool.misc import random_hash
from cftool.misc import print_warning
from cftool.data_structures import Item
from cftool.data_structures import QueuesInQueue

from cfdraw.app.schema import IRequestQueue
from cfdraw.app.schema import IRequestQueueData
from cfdraw.core.toolkit import console
from cfdraw.utils.misc import offload
from cfdraw.schema.plugins import ISend
from cfdraw.schema.plugins import SocketStatus
from cfdraw.schema.plugins import ISocketMessage
from cfdraw.core.toolkit.misc import get_err_msg
from cfdraw.core.toolkit.misc import random_hash
from cfdraw.core.toolkit.data_structures import Item
from cfdraw.core.toolkit.data_structures import Bundle
from cfdraw.core.toolkit.data_structures import TItemData


DEBUG = False


class QueuesInQueue(Generic[TItemData]):
def __init__(self, *, no_mapping: bool = True) -> None:
self._cursor = 0
self._queues: Bundle[Bundle[TItemData]] = Bundle(no_mapping=no_mapping)

def __iter__(self) -> Iterator[Item[Bundle[TItemData]]]:
return iter(self._queues)

@property
def is_empty(self) -> bool:
return self.num_items == 0

@property
def num_queues(self) -> int:
return len(self._queues)

@property
def num_items(self) -> int:
return sum(len(q.data) for q in self._queues)

def get(self, queue_id: str) -> Optional[Item[Bundle[TItemData]]]:
return self._queues.get(queue_id)

def push(self, queue_id: str, item: Item[TItemData]) -> None:
queue_item = self._queues.get(queue_id)
if queue_item is not None:
queue = queue_item.data
else:
queue = Bundle()
self._queues.push(Item(queue_id, queue))
queue.push(item)

def next(self) -> Tuple[Optional[str], Optional[Item[TItemData]]]:
if self._queues.is_empty:
return None, None
self._cursor %= len(self._queues)
queue = self._queues.get_index(self._cursor)
item = queue.data.first
if item is None:
self._queues.remove(queue.key)
return self.next()
self._cursor += 1
return queue.key, item

def remove(self, queue_id: str, item_key: str) -> None:
queue_item = self._queues.get(queue_id)
if queue_item is None:
return
queue_item.data.remove(item_key)
if queue_item.data.is_empty:
self._queues.remove(queue_id)

def get_pending(self, item_key: str) -> Optional[List[Item[TItemData]]]:
if self._queues.is_empty:
return None
layer = 0
searched = False
pending: List[Item[TItemData]] = []
finished_searching = [False] * len(self._queues)

init = (self._cursor + len(self._queues) - 1) % len(self._queues)
cursor = init
while not all(finished_searching):
if not finished_searching[cursor]:
queue = self._queues.get_index(cursor)
if layer >= len(queue.data):
finished_searching[cursor] = True
else:
item = queue.data.get_index(layer)
if item.key == item_key:
searched = True
break
pending.append(item)
cursor = (cursor + 1) % len(self._queues)
if cursor == init:
layer += 1

return pending if searched else None


class RequestQueue(IRequestQueue):
def __init__(self) -> None:
self._queues = QueuesInQueue[IRequestQueueData]()
Expand Down Expand Up @@ -79,11 +162,11 @@ async def wait(self, user_id: str, uid: str) -> None:
# So here we simply warn instead of raise.
queue_item = self._queues.get(user_id)
if queue_item is None:
print_warning("cannot find user request queue after submitted")
console.warn("cannot find user request queue after submitted")
return
request_item = queue_item.data.get(uid)
if request_item is None:
print_warning("cannot find request item after submitted")
console.warn("cannot find request item after submitted")
return
await self._broadcast_pending()
asyncio.create_task(self.run())
Expand Down Expand Up @@ -144,7 +227,7 @@ async def _broadcast_pending(self) -> None:
except Exception:
logging.exception(f"{prefix} failed to send message '{message}'")
if not success:
print_error(f"Failed to send following message: {message}")
console.error(f"Failed to send following message: {message}")

async def _broadcast_working(self, uid: str) -> bool:
sender_pack = self._senders.get(uid)
Expand All @@ -167,7 +250,7 @@ async def _broadcast_working(self, uid: str) -> bool:
except Exception:
logging.exception(f"{prefix} failed to send message '{message}'")
if not success:
print_error(f"Failed to send following message: {message}")
console.error(f"Failed to send following message: {message}")
return success

async def _broadcast_exception(self, uid: str, message: str) -> bool:
Expand All @@ -184,7 +267,7 @@ async def _broadcast_exception(self, uid: str, message: str) -> bool:
except Exception:
logging.exception(f"{prefix} failed to send message '{message}'")
if not success:
print_error(f"Failed to send following message: {message}")
console.error(f"Failed to send following message: {message}")
return success


Expand Down
6 changes: 3 additions & 3 deletions cfdraw/app/endpoints/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
from fastapi import UploadFile
from pydantic import BaseModel
from PIL.PngImagePlugin import PngInfo
from cftool.web import get_responses
from cftool.web import get_image_response_kwargs
from cftool.misc import get_err_msg

from cfdraw import constants
from cfdraw.app.schema import IApp
Expand All @@ -23,6 +20,9 @@
from cfdraw.utils.server import get_svg_response
from cfdraw.utils.server import get_image_response
from cfdraw.app.endpoints.base import IEndpoint
from cfdraw.core.toolkit.web import get_responses
from cfdraw.core.toolkit.web import get_image_response_kwargs
from cfdraw.core.toolkit.misc import get_err_msg


class ImageDataModel(BaseModel):
Expand Down
6 changes: 3 additions & 3 deletions cfdraw/app/endpoints/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

from fastapi import WebSocket
from fastapi import WebSocketDisconnect
from cftool.misc import get_err_msg
from cftool.misc import print_error
from starlette.websockets import WebSocketState

from cfdraw import constants
from cfdraw.app.schema import IApp
from cfdraw.app.schema import IRequestQueueData
from cfdraw.core.toolkit import console
from cfdraw.utils.misc import offload
from cfdraw.schema.plugins import ElapsedTimes
from cfdraw.schema.plugins import ISocketRequest
from cfdraw.schema.plugins import ISocketMessage
from cfdraw.app.endpoints.base import IEndpoint
from cfdraw.core.toolkit.misc import get_err_msg


def add_websocket(app: IApp) -> None:
Expand Down Expand Up @@ -72,7 +72,7 @@ async def send_message(data: ISocketMessage) -> bool:
)
exception = ISocketMessage.make_exception(data.hash, message)
if not await send_message(exception):
print_error(f"[websocket.loop] {message}")
console.error(f"\[websocket.loop] {message}")
except WebSocketDisconnect:
break
except Exception as e:
Expand Down
11 changes: 5 additions & 6 deletions cfdraw/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import pkg_resources

from pathlib import Path
from cftool.misc import print_info

from cfdraw import constants
from cfdraw.utils import exec
from cfdraw.utils import console
from cfdraw.utils import processes
from cfdraw.utils import prerequisites
from cfdraw.config import get_config
from cfdraw.core.toolkit import console
from cfdraw.utils.template import set_init_codes
from cfdraw.utils.template import TemplateType

Expand Down Expand Up @@ -52,7 +51,7 @@ def run(
pkg_resources.require(requirements)
except Exception as err:
console.rule("📦 Installing Requirements")
print_info(f"Reason : {err}")
console.log(f"Reason : {err}")
enclosed = lambda s: f'"{s}"'
requirements_string = " ".join(map(enclosed, requirements))
cmd = f"{sys.executable} -m pip install {requirements_string}"
Expand Down Expand Up @@ -90,11 +89,11 @@ def run(
backend_fn(module, log_level=log_level)
finally:
console.rule("[bold]Shutting down")
print_info("Killing frontend")
console.log("Killing frontend")
processes.kill_process_on_port(frontend_port)
print_info("Killing backend")
console.log("Killing backend")
processes.kill_process_on_port(backend_port)
print_info("Done")
console.log("Done")


@cli.command()
Expand Down
Empty file added cfdraw/core/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions cfdraw/core/flow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .core import *
from .nodes import *
from .server import *
from .utils import *
from .docs import *
Loading

0 comments on commit e337f79

Please sign in to comment.