feat: 重命名项目为Boardware Genius并添加运行时环境同步功能

- 将项目品牌从nanobot重命名为Boardware Genius,更新所有相关文档、注释和日志输出
- 在web服务器中添加运行时环境变量同步功能,支持授权和后端身份配置
- 更新create-instance脚本以生成运行时环境文件
- 添加实例后端绑定功能到部署控制服务
- 修改入口脚本以加载运行时环境变量
- 更新前端和认证门户的相关描述文本
This commit is contained in:
2026-03-18 15:45:42 +08:00
parent b6dd0c1623
commit 4e45f8b717
36 changed files with 315 additions and 76 deletions

View File

@ -282,6 +282,98 @@ def create_or_get_instance(payload: dict[str, Any]) -> dict[str, Any]:
}
def _upsert_registry_record(record: dict[str, Any]) -> dict[str, Any]:
instance_id = str(record.get("instance_id", "") or "").strip()
if not instance_id:
raise ApiError(HTTPStatus.BAD_GATEWAY, "registry record is missing instance_id")
command = [
str(REGISTRY_TOOL),
"--registry",
str(REGISTRY_PATH),
"upsert",
"--instance-id",
instance_id,
"--instance-slug",
str(record.get("instance_slug", "") or "").strip(),
"--container-name",
str(record.get("container_name", "") or "").strip(),
"--image-name",
str(record.get("image_name", "") or "").strip(),
"--host-port",
str(int(record.get("host_port", 0) or 0)),
"--public-url",
str(record.get("public_url", "") or "").strip(),
"--instance-root",
str(record.get("instance_root", "") or "").strip(),
"--nanobot-home",
str(record.get("nanobot_home", "") or "").strip(),
"--config-path",
str(record.get("config_path", "") or "").strip(),
"--auth-users-path",
str(record.get("auth_users_path", "") or "").strip(),
"--network-name",
str(record.get("network_name", "") or "").strip(),
"--backend-id",
str(record.get("backend_id", "") or "").strip(),
"--backend-name",
str(record.get("backend_name", "") or "").strip(),
"--authz-base-url",
str(record.get("authz_base_url", "") or "").strip(),
"--username",
str(record.get("username", "") or "").strip(),
"--email",
str(record.get("email", "") or "").strip(),
"--instance-host",
str(record.get("instance_host", "") or "").strip(),
"--frontend-base-url",
str(record.get("frontend_base_url", "") or "").strip(),
"--api-base-url",
str(record.get("api_base_url", "") or "").strip(),
"--created-at",
str(record.get("created_at", "") or "").strip(),
]
run_command(command, cwd=APP_INSTANCE_DIR)
updated = get_registry_record(instance_id=instance_id)
if updated is None:
raise ApiError(HTTPStatus.BAD_GATEWAY, "registry record update did not persist")
return updated
def bind_instance_backend(payload: dict[str, Any]) -> dict[str, Any]:
instance_id = str(payload.get("instance_id", "") or "").strip()
username = str(payload.get("username", "") or "").strip()
backend_id = str(payload.get("backend_id", "") or "").strip()
backend_name = str(payload.get("backend_name", "") or "").strip()
authz_base_url = str(payload.get("authz_base_url", "") or "").strip()
if not backend_id:
raise ApiError(HTTPStatus.BAD_REQUEST, "backend_id is required")
if not instance_id and not username:
raise ApiError(HTTPStatus.BAD_REQUEST, "instance_id or username is required")
record = None
if instance_id:
record = get_registry_record(instance_id=instance_id)
if record is None and username:
record = get_registry_record(username=username)
if record is None:
raise ApiError(HTTPStatus.NOT_FOUND, "instance not found")
updated_record = dict(record)
updated_record["backend_id"] = backend_id
updated_record["backend_name"] = backend_name or str(record.get("backend_name", "") or "").strip() or backend_id
if authz_base_url:
updated_record["authz_base_url"] = authz_base_url
updated = _upsert_registry_record(updated_record)
return {
"instance": updated,
"public_url": str(updated.get("public_url", "") or ""),
"frontend_base_url": str(updated.get("frontend_base_url", "") or updated.get("public_url", "") or ""),
"api_base_url": build_internal_api_base_url(updated),
}
def resolve_instance(payload: dict[str, Any]) -> dict[str, Any]:
username = str(payload.get("username", "") or "").strip()
if not username:
@ -367,6 +459,10 @@ class Handler(BaseHTTPRequestHandler):
payload = self._read_json_body()
self._json_response(HTTPStatus.OK, create_or_get_instance(payload))
return
if self.path == "/api/instances/bind-backend":
payload = self._read_json_body()
self._json_response(HTTPStatus.OK, bind_instance_backend(payload))
return
if self.path == "/api/instances/resolve":
payload = self._read_json_body()
self._json_response(HTTPStatus.OK, resolve_instance(payload))