refactor: move routes under /tori/ prefix and add /api/obj mount
Routes now live at /tori/api, /ws/tori, and static files at /tori/. Root / redirects to /tori/. Object storage mounted at /api/obj. Dev proxy updated accordingly.
This commit is contained in:
20
src/main.rs
20
src/main.rs
@@ -5,7 +5,9 @@ mod kb;
|
|||||||
mod llm;
|
mod llm;
|
||||||
mod exec;
|
mod exec;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
mod template;
|
||||||
mod timer;
|
mod timer;
|
||||||
|
mod tools;
|
||||||
mod ws;
|
mod ws;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -19,6 +21,7 @@ pub struct AppState {
|
|||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub agent_mgr: Arc<agent::AgentManager>,
|
pub agent_mgr: Arc<agent::AgentManager>,
|
||||||
pub kb: Option<Arc<kb::KbManager>>,
|
pub kb: Option<Arc<kb::KbManager>>,
|
||||||
|
pub obj_root: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Deserialize)]
|
||||||
@@ -83,17 +86,28 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
// Resume incomplete workflows after restart
|
// Resume incomplete workflows after restart
|
||||||
resume_workflows(database.pool.clone(), agent_mgr.clone()).await;
|
resume_workflows(database.pool.clone(), agent_mgr.clone()).await;
|
||||||
|
|
||||||
|
let obj_root = std::env::var("OBJ_ROOT").unwrap_or_else(|_| "/data/obj".to_string());
|
||||||
|
|
||||||
let state = Arc::new(AppState {
|
let state = Arc::new(AppState {
|
||||||
db: database,
|
db: database,
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
agent_mgr: agent_mgr.clone(),
|
agent_mgr: agent_mgr.clone(),
|
||||||
kb: kb_arc,
|
kb: kb_arc,
|
||||||
|
obj_root: obj_root.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.nest("/api", api::router(state))
|
.nest("/tori/api", api::router(state))
|
||||||
.nest("/ws", ws::router(agent_mgr))
|
.nest("/api/obj", api::obj::router(obj_root.clone()))
|
||||||
.fallback_service(ServeDir::new("web/dist").fallback(ServeFile::new("web/dist/index.html")))
|
.route("/api/obj/", axum::routing::get({
|
||||||
|
let r = obj_root;
|
||||||
|
move || api::obj::root_listing(r)
|
||||||
|
}))
|
||||||
|
.nest("/ws/tori", ws::router(agent_mgr))
|
||||||
|
.nest_service("/tori", ServeDir::new("web/dist").fallback(ServeFile::new("web/dist/index.html")))
|
||||||
|
.route("/", axum::routing::get(|| async {
|
||||||
|
axum::response::Redirect::permanent("/tori/")
|
||||||
|
}))
|
||||||
.layer(CorsLayer::permissive());
|
.layer(CorsLayer::permissive());
|
||||||
|
|
||||||
let addr = format!("{}:{}", &config.server.host, config.server.port);
|
let addr = format!("{}:{}", &config.server.host, config.server.port);
|
||||||
|
|||||||
8
web/package-lock.json
generated
8
web/package-lock.json
generated
@@ -1127,6 +1127,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz",
|
||||||
"integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==",
|
"integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
@@ -1324,6 +1325,7 @@
|
|||||||
"version": "11.1.2",
|
"version": "11.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz",
|
||||||
"integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==",
|
"integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chevrotain/cst-dts-gen": "11.1.2",
|
"@chevrotain/cst-dts-gen": "11.1.2",
|
||||||
"@chevrotain/gast": "11.1.2",
|
"@chevrotain/gast": "11.1.2",
|
||||||
@@ -1374,6 +1376,7 @@
|
|||||||
"version": "3.33.1",
|
"version": "3.33.1",
|
||||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
|
||||||
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
|
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
@@ -1740,6 +1743,7 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
@@ -2136,6 +2140,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -2314,6 +2319,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -2350,6 +2356,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -2466,6 +2473,7 @@
|
|||||||
"version": "3.5.29",
|
"version": "3.5.29",
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.29.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.29.tgz",
|
||||||
"integrity": "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==",
|
"integrity": "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.29",
|
"@vue/compiler-dom": "3.5.29",
|
||||||
"@vue/compiler-sfc": "3.5.29",
|
"@vue/compiler-sfc": "3.5.29",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Project, Workflow, ExecutionLogEntry, Comment, Timer, KbArticle, KbArticleSummary, PlanStepInfo, LlmCallLogEntry } from './types'
|
import type { Project, Workflow, ExecutionLogEntry, Comment, Timer, KbArticle, KbArticleSummary, PlanStepInfo, LlmCallLogEntry } from './types'
|
||||||
|
|
||||||
const BASE = '/api'
|
const BASE = `${import.meta.env.BASE_URL.replace(/\/$/, '')}/api`
|
||||||
|
|
||||||
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||||||
const res = await fetch(`${BASE}${path}`, {
|
const res = await fetch(`${BASE}${path}`, {
|
||||||
@@ -102,4 +102,12 @@ export const api = {
|
|||||||
|
|
||||||
deleteArticle: (id: string) =>
|
deleteArticle: (id: string) =>
|
||||||
request<boolean>(`/kb/articles/${id}`, { method: 'DELETE' }),
|
request<boolean>(`/kb/articles/${id}`, { method: 'DELETE' }),
|
||||||
|
|
||||||
|
getSettings: () => request<Record<string, string>>('/settings'),
|
||||||
|
|
||||||
|
putSetting: (key: string, value: string) =>
|
||||||
|
request<Record<string, string>>(`/settings/${key}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ value }),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ export type WsHandler = (msg: WsMessage) => void
|
|||||||
|
|
||||||
export function connectWs(projectId: string, onMessage: WsHandler): { close: () => void } {
|
export function connectWs(projectId: string, onMessage: WsHandler): { close: () => void } {
|
||||||
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
|
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||||
const url = `${proto}//${location.host}/ws/${projectId}`
|
const wsBase = import.meta.env.BASE_URL.replace(/\/$/, '')
|
||||||
|
const url = `${proto}//${location.host}/ws${wsBase}/${projectId}`
|
||||||
let ws: WebSocket | null = null
|
let ws: WebSocket | null = null
|
||||||
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
let closed = false
|
let closed = false
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import { defineConfig } from 'vite'
|
|||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: process.env.VITE_BASE_PATH || '/tori/',
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://localhost:3000',
|
'/tori/api': 'http://localhost:3000',
|
||||||
'/ws': {
|
'/api/obj': 'http://localhost:3000',
|
||||||
|
'/ws/tori': {
|
||||||
target: 'ws://localhost:3000',
|
target: 'ws://localhost:3000',
|
||||||
ws: true,
|
ws: true,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user