Skip to content

Commit

Permalink
now server can be launched in cli
Browse files Browse the repository at this point in the history
  • Loading branch information
visualDust committed Nov 26, 2023
1 parent 364950b commit af01e30
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 100 deletions.
107 changes: 57 additions & 50 deletions neetbox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,75 +1,82 @@
import os
import sys

import toml

from neetbox.config import default as default_config
from neetbox.config import get_module_level_config
from neetbox.config._config import update_with
from neetbox.daemon import _try_attach_daemon
from neetbox.config._config import update_workspace_config_with
from neetbox.logging.formatting import LogStyle
from neetbox.logging.logger import Logger
from neetbox.utils.framing import get_frame_module_traceback

module = get_frame_module_traceback(1).__name__ # type: ignore
config_file_name = f"{module}.toml"
logger = Logger("NEETBOX", style=LogStyle(with_datetime=False, skip_writers=["ws"]))

MODULE_NAME = get_frame_module_traceback(1).__name__ # type: ignore
CONFIG_FILE_NAME = f"{MODULE_NAME}.toml"

def init(path=None, load=False, **kwargs) -> bool:

def _init_workspace(path=None, **kwargs) -> bool:
if path:
os.chdir(path=path)
current_path = os.getcwd()
config_file_path = os.path.join(current_path, config_file_name)
logger = Logger("NEETBOX", style=LogStyle(with_datetime=False, skip_writers=["ws"]))
if not load:
if not os.path.isfile(config_file_path): # config file not exist
try: # creating config file using default config
with open(config_file_path, "w+") as config_file:
_config = dict(default_config)
if "name" in kwargs and kwargs["name"]: # using given name
_config["name"] = kwargs["name"]
else: # using the folder name
_config["name"] = os.path.basename(os.path.normpath(os.getcwd()))
toml.dump(_config, config_file)
logger.ok(f"Workspace config created as {config_file_path}.")
return True
except Exception as e:
logger.err(f"Failed to create {config_file_path}: {e}")
return False
else: # config file exist:
logger.err((f"Config file already exists.")) # noqa
return False
else: # if load only
if not os.path.isfile(config_file_path): # but config file not exist
logger.err(f"Config file {config_file_path} not exists.")
config_file_path = os.path.join(current_path, CONFIG_FILE_NAME)
if not os.path.isfile(config_file_path): # config file not exist
try: # creating config file using default config
with open(config_file_path, "w+") as config_file:
_config = dict(default_config)
if "name" in kwargs and kwargs["name"]: # using given name
_config["name"] = kwargs["name"]
else: # using the folder name
_config["name"] = os.path.basename(os.path.normpath(os.getcwd()))
toml.dump(_config, config_file)
logger.ok(f"Workspace config created as {config_file_path}.")
except Exception as e:
logger.err(f"Failed to create {config_file_path}: {e}")
return False
else: # config file exist:
logger.err((f"Config file already exists.")) # noqa
return False

try: # do load only

def _load_workspace(path=None) -> bool:
if path:
os.chdir(path=path)
current_path = os.getcwd()
config_file_path = os.path.join(current_path, CONFIG_FILE_NAME)
if not os.path.isfile(config_file_path): # but config file not exist
logger.err(f"Config file {config_file_path} not exists.")
return False
try: # do load
load_config = toml.load(config_file_path)
update_with(load_config)
logger.ok(f"found workspace config from {config_file_path}.")
_try_attach_daemon() # try attach daemon
logger.debug(f"running post init...")
update_workspace_config_with(load_config)
logger.ok(f"workspace config loaded from {config_file_path}.")
return True
except Exception as e:
logger.err(f"failed to load config from {config_file_path}: {e}")
raise e


def post_init():
import setproctitle

project_name = get_module_level_config()["name"]
setproctitle.setproctitle(project_name)
logger.err(f"failed to load workspace config from {config_file_path}: {e}")
return False


is_in_daemon_process = (
"NEETBOX_DAEMON_PROCESS" in os.environ and os.environ["NEETBOX_DAEMON_PROCESS"] == "1"
)
# print('prevent_daemon_loading =', is_in_daemon_process)
if os.path.isfile(config_file_name) and not is_in_daemon_process: # if in a workspace
# todo check if running in cli mode
success = init(load=True) # init from config file
if not success:


def _load_workspace_and_attach_daemon():
success = _load_workspace() # init from config file
if not success: # failed to load workspace config, exiting
os._exit(255)
# run post init
post_init()
# try attach daemon
from neetbox.daemon import _try_attach_daemon

_try_attach_daemon()


def _is_in_workspace():
return os.path.isfile(CONFIG_FILE_NAME)


if len(sys.argv) > 0 and sys.argv[0].endswith("neet") or is_in_daemon_process:
# running in cli or daemon process, do not load workspace
pass
elif _is_in_workspace(): # if a config file exist and not running in cli
_load_workspace_and_attach_daemon()
28 changes: 27 additions & 1 deletion neetbox/cli/parse.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import json
import os

import click

import neetbox
import neetbox.daemon.server as server_module
from neetbox.config import get_module_level_config
from neetbox.daemon.client._client_apis import *
from neetbox.daemon.server._server import server_process
from neetbox.logging.formatting import LogStyle
from neetbox.logging.logger import Logger

Expand All @@ -24,9 +28,17 @@ def main(ctx, verbose: bool):
ctx.obj["verbose"] = verbose


def _try_load_workspace_if_applicable():
if neetbox._is_in_workspace():
success = neetbox._load_workspace()
if not success:
os._exit(255)


@main.command(name="list")
def list_command():
"""Show list of connected project names"""
_try_load_workspace_if_applicable()
try:
_list_json = get_list()
click.echo(json.dumps(_list_json))
Expand All @@ -38,6 +50,7 @@ def list_command():
@click.argument("name")
def status_command(name):
"""Show the working tree status"""
_try_load_workspace_if_applicable()
_stat_json = None
try:
_stat_json = get_status_of(name)
Expand All @@ -46,12 +59,25 @@ def status_command(name):
logger.log("Could not fetch data. Is there any project with NEETBOX running?")


@main.command(name="serve")
@click.option("--port", "-p", help="specify which port to launch", metavar="port", required=False)
def serve(port: int):
"""serve neetbox server in attached mode"""
_try_load_workspace_if_applicable()
try:
server_config = get_module_level_config(server_module)
logger.log(f"Launching server using config: {server_config}")
server_process(cfg=server_config)
except Exception as e:
logger.err(f"Failed to launch a neetbox server: {e}")


@main.command()
@click.option("--name", "-n", help="set project name", metavar="name", required=False)
def init(name: str):
"""initialize current folder as workspace and generate the config file from defaults"""
try:
if neetbox.init(name=name):
if neetbox._init_workspace(name=name):
logger.skip_lines(2)
logger.console_banner("neetbox", font="ansishadow")
logger.log("Welcome to NEETBOX")
Expand Down
2 changes: 1 addition & 1 deletion neetbox/config/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
WORKSPACE_CONFIG: dict = DEFAULT_WORKSPACE_CONFIG.copy()


def update_with(cfg: dict):
def update_workspace_config_with(cfg: dict):
def _update_dict_recursively(self: dict, the_other: dict):
for _k, _v in the_other.items():
if type(_v) is dict: # currently resolving a dict child
Expand Down
5 changes: 2 additions & 3 deletions neetbox/daemon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from neetbox.daemon.server.daemonable_process import DaemonableProcess
from neetbox.logging.formatting import LogStyle
from neetbox.logging.logger import Logger
from neetbox.pipeline import listen, watch

logger = Logger(style=LogStyle(with_datetime=False, skip_writers=["ws"]))

Expand Down Expand Up @@ -42,7 +41,7 @@ def __attach_daemon(daemon_config):
)
return False

logger.warn(
logger.log(
f"No daemon running at {daemon_config['host']}:{daemon_config['port']}, trying to create daemon..."
)

Expand Down Expand Up @@ -87,4 +86,4 @@ def _try_attach_daemon():

action = NeetActionManager.register
ws_subscribe = connection.ws_subscribe
__all__ = ["watch", "listen", "action", "ws_subscribe", "NeetActionManager", "_try_attach_daemon"]
__all__ = ["action", "ws_subscribe", "NeetActionManager", "_try_attach_daemon"]
12 changes: 7 additions & 5 deletions neetbox/daemon/client/_client_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
from neetbox.daemon._protocol import *
from neetbox.daemon.client._client import connection

__cfg = get_module_level_config()
daemon_address = f"{__cfg['host']}:{__cfg['port']}"
base_addr = f"http://{daemon_address}/"

def get_base_addr():
__cfg = get_module_level_config()
daemon_address = f"{__cfg['host']}:{__cfg['port']}"
return f"http://{daemon_address}/"


def _fetch(url):
Expand All @@ -21,10 +23,10 @@ def _fetch(url):


def get_list():
api_addr = f"{base_addr}{FRONTEND_API_ROOT}/list"
api_addr = f"{get_base_addr()}{FRONTEND_API_ROOT}/list"
return _fetch(api_addr)


def get_status_of(name):
api_addr = f"{base_addr}{FRONTEND_API_ROOT}/status/{name}"
api_addr = f"{get_base_addr()}{FRONTEND_API_ROOT}/status/{name}"
return _fetch(api_addr)
4 changes: 2 additions & 2 deletions neetbox/daemon/server/_daemon_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
import sys

from neetbox.daemon.server._server import daemon_process
from neetbox.daemon.server._server import server_process

# sys.stdout=open(r'D:\Projects\ML\neetbox\logdir\daemon.log', 'a+')

Expand All @@ -19,7 +19,7 @@ def run():
args = ap.parse_args()
daemon_config = json.loads(args.config)
print("Daemon started with config:", daemon_config)
daemon_process(daemon_config)
server_process(daemon_config)


print("_daemon_ is starting with __name__ =", __name__, " and args =", sys.argv)
Expand Down
37 changes: 21 additions & 16 deletions neetbox/daemon/server/_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import os

import werkzeug
from rich.console import Console

console = Console()
Expand All @@ -28,7 +29,7 @@
from neetbox.daemon._protocol import *

import setproctitle
from flask import abort, json, request
from flask import abort, json, request, send_from_directory
from websocket_server import WebsocketServer

__DAEMON_SHUTDOWN_IF_NO_UPLOAD_TIMEOUT_SEC = 60 * 60 * 12 # 12 Hours
Expand All @@ -37,7 +38,7 @@
setproctitle.setproctitle(__PROC_NAME)


def daemon_process(cfg, debug=False):
def server_process(cfg, debug=False):
# describe a client
class Bridge:
connected: bool
Expand All @@ -60,6 +61,7 @@ def ws_send(self):

# ===============================================================

print()
if debug:
console.log(f"Running with debug, using APIFlask")
from apiflask import APIFlask
Expand Down Expand Up @@ -285,6 +287,19 @@ def send_to_client_of_name(name, message):
# ws_send(data, to=target_sid)
# return "ok"

front_end_dist_path = os.path.join(os.path.dirname(__file__), "../../frontend/dist")

@app.route("/")
def static_serve_root():
return send_from_directory(front_end_dist_path, "index.html")

@app.route("/<path:name>")
def static_serve(name):
try:
return send_from_directory(front_end_dist_path, name)
except werkzeug.exceptions.NotFound:
return send_from_directory(front_end_dist_path, "index.html")

@app.route("/hello", methods=["GET"])
def just_send_hello():
return json.dumps({"hello": "hello"})
Expand Down Expand Up @@ -329,22 +344,12 @@ def __sleep_and_shutdown(secs=3):
console.log(f"BYE.")
return f"shutdown in {3} seconds."

def _count_down_thread():
global __COUNT_DOWN
while True:
__COUNT_DOWN -= 1
if not __COUNT_DOWN:
sys.exit(0)
time.sleep(1)

count_down_thread = Thread(target=_count_down_thread, daemon=True)
count_down_thread.start()

console.log(f"launching websocket server...")
ws_server.run_forever(threaded=True)

console.log(f"launching flask server...")
app.run(host="0.0.0.0", port=cfg["port"])
_port = cfg["port"]
console.log(f"visit server at http://localhost:{_port}")
app.run(host="0.0.0.0", port=_port)


if __name__ == "__main__":
Expand All @@ -358,4 +363,4 @@ def _count_down_thread():
"mode": "detached",
"uploadInterval": 10,
}
daemon_process(cfg, debug=True)
server_process(cfg, debug=True)
2 changes: 1 addition & 1 deletion neetbox/frontend/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import useSWR, { mutate } from "swr";
export const API_BASEURL = "/web";
export const WEBSOCKET_URL = import.meta.env.DEV
? "ws://localhost:5001"
: `ws://${location.hostname}:${Number(location.port) + 1}}`;
: `ws://${location.hostname}:${Number(location.port) + 1}`;

async function fetcher(url: string) {
const res = await fetch(API_BASEURL + url);
Expand Down
4 changes: 0 additions & 4 deletions neetbox/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,4 @@
from neetbox.logging.logger import DEFAULT_LOGGER as logger
from neetbox.logging.logger import set_log_level

_cfg = get_module_level_config()
logger.set_log_dir(_cfg["logdir"])
set_log_level(_cfg["level"])

__all__ = ["logger"]
Loading

0 comments on commit af01e30

Please sign in to comment.