diff --git a/internal/app/app.go b/internal/app/app.go index 93d7ca5..3b78fd5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,16 +2,13 @@ package app import ( "context" - "errors" "fmt" "io" "io/fs" "log/slog" - "net" "net/http" "os" "path/filepath" - "strings" "time" "github.com/havline/havline/internal/acme" @@ -147,9 +144,6 @@ func New(cfg config.Config, staticFS fs.FS, migrationsDir string) (*App, error) StaticFS: staticFS, StartedAt: startedAt, }) - if prefix := strings.TrimSpace(cfg.GatewayPrefix); prefix != "" { - handler = stripPrefixIfPresent(prefix, handler) - } server := &http.Server{ Addr: cfg.ListenAddr, Handler: handler, @@ -241,33 +235,7 @@ func (a *App) bootstrapNginx(ctx context.Context, proxySvc *service.ProxyService } func (a *App) Run() error { - errCh := make(chan error, 2) - go func() { - errCh <- a.server.ListenAndServe() - }() - - if socket := strings.TrimSpace(a.cfg.GatewaySocket); socket != "" { - if err := os.Remove(socket); err != nil && !os.IsNotExist(err) { - return err - } - listener, err := net.Listen("unix", socket) - if err != nil { - return err - } - if err := os.Chmod(socket, 0o660); err != nil { - _ = listener.Close() - return err - } - go func() { - errCh <- a.server.Serve(listener) - }() - } - - err := <-errCh - if errors.Is(err, http.ErrServerClosed) { - return nil - } - return err + return a.server.ListenAndServe() } func (a *App) Shutdown(ctx context.Context) error { @@ -278,9 +246,6 @@ func (a *App) Shutdown(ctx context.Context) error { if err := a.server.Shutdown(ctx); err != nil { return err } - if socket := strings.TrimSpace(a.cfg.GatewaySocket); socket != "" { - _ = os.Remove(socket) - } if err := a.nginx.Stop(ctx); err != nil { a.logger.Error("nginx stop failed", "module", "NGINX", "error", err.Error()) } @@ -295,18 +260,6 @@ func (a *App) Shutdown(ctx context.Context) error { return nil } -func stripPrefixIfPresent(prefix string, next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if strings.HasPrefix(r.URL.Path, prefix) { - r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix) - if r.URL.Path == "" { - r.URL.Path = "/" - } - } - next.ServeHTTP(w, r) - }) -} - func ResolveMigrationsDir() (string, error) { candidates := []string{ "migrations", diff --git a/internal/config/config.go b/internal/config/config.go index 951a290..361df71 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,8 +12,6 @@ import ( type Config struct { ListenAddr string - GatewaySocket string - GatewayPrefix string DataDir string SessionSecret string NginxBin string @@ -33,8 +31,6 @@ func Load() Config { } return Config{ ListenAddr: envOr("HAVLINE_LISTEN", ":6893"), - GatewaySocket: envOr("HAVLINE_GATEWAY_SOCKET", ""), - GatewayPrefix: envOr("HAVLINE_GATEWAY_PREFIX", ""), DataDir: dataDir, SessionSecret: envOr("HAVLINE_SESSION_SECRET", ""), NginxBin: envOr("HAVLINE_NGINX_BIN", "nginx"), diff --git a/web/src/api/base.ts b/web/src/api/base.ts deleted file mode 100644 index 4cef78a..0000000 --- a/web/src/api/base.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const APP_BASE = import.meta.env.BASE_URL.replace(/\/$/, '') - -export function withBase(path: string): string { - if (!path.startsWith('/')) return path - return `${APP_BASE}${path}` -} diff --git a/web/src/api/client.ts b/web/src/api/client.ts index 517b626..4bd3200 100644 --- a/web/src/api/client.ts +++ b/web/src/api/client.ts @@ -51,7 +51,6 @@ import type { CfPreflightResult, CfRouteTestResult, } from './types' -import { withBase } from './base' export function asList(value: T[] | null | undefined): T[] { return Array.isArray(value) ? value : [] @@ -80,7 +79,7 @@ async function request(path: string, init?: RequestInit, timeoutMs = REQUEST_ } async function requestWithSignal(path: string, init?: RequestInit, signal?: AbortSignal): Promise { - const response = await fetch(withBase(path), { + const response = await fetch(path, { credentials: 'include', signal, headers: { @@ -180,7 +179,7 @@ export const api = { email: payload.email ?? '', }), }), - certificateApplyStreamURL: (jobId: string) => withBase(`/api/certificates/jobs/${encodeURIComponent(jobId)}/stream`), + certificateApplyStreamURL: (jobId: string) => `/api/certificates/jobs/${encodeURIComponent(jobId)}/stream`, importCertificate: (payload: { certificate?: string private_key?: string @@ -193,7 +192,7 @@ export const api = { }), async downloadCertificate(domain: string, part: 'zip' | 'cert' | 'key' = 'zip') { const response = await fetch( - withBase(`/api/certificates/${encodeURIComponent(domain)}/download?part=${part}`), + `/api/certificates/${encodeURIComponent(domain)}/download?part=${part}`, { credentials: 'include' }, ) if (!response.ok) { @@ -433,7 +432,7 @@ export const api = { }, async exportBackup() { - const response = await fetch(withBase('/api/backup/export'), { credentials: 'include' }) + const response = await fetch('/api/backup/export', { credentials: 'include' }) if (!response.ok) { throw new Error('导出备份失败') } @@ -455,7 +454,7 @@ export const api = { deleteBackupArchive: (name: string) => request<{ ok: boolean }>(`/api/backup/archives/${encodeURIComponent(name)}`, { method: 'DELETE' }), async downloadBackupArchive(name: string) { - const response = await fetch(withBase(`/api/backup/archives/${encodeURIComponent(name)}`), { credentials: 'include' }) + const response = await fetch(`/api/backup/archives/${encodeURIComponent(name)}`, { credentials: 'include' }) if (!response.ok) { throw new Error('下载备份失败') } @@ -471,7 +470,7 @@ export const api = { async restoreBackup(file: File) { const form = new FormData() form.append('file', file) - const response = await fetch(withBase('/api/backup/restore'), { + const response = await fetch('/api/backup/restore', { method: 'POST', credentials: 'include', body: form, diff --git a/web/src/router/index.ts b/web/src/router/index.ts index 3466b9c..cc9477c 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -17,7 +17,7 @@ import StatusPageView from '../views/StatusPageView.vue' import AboutView from '../views/AboutView.vue' const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), + history: createWebHistory(), routes: [ { path: '/setup', redirect: '/login' }, { path: '/login', name: 'login', component: LoginView, meta: { public: true } }, diff --git a/web/src/views/ProxyView.vue b/web/src/views/ProxyView.vue index aaebb42..9ca6443 100644 --- a/web/src/views/ProxyView.vue +++ b/web/src/views/ProxyView.vue @@ -912,7 +912,6 @@ import { WarningOutline, } from '@vicons/ionicons5' import { api, asList } from '../api/client' -import { withBase } from '../api/base' import type { CfTunnel, DiscoveredService, ProxyClientConn, ProxyRule, ProxySavePayload, ProxyTraffic } from '../api/types' import { useVisibilityPolling } from '../composables/useVisibilityPolling' import EmptyState from '../components/EmptyState.vue' @@ -1836,7 +1835,7 @@ function stopLogStream() { function startLogStream() { const rule = selectedRule.value if (!rule || logEventSource) return - logEventSource = new EventSource(withBase(`/api/proxies/${rule.id}/logs/stream?tail=100`), { + logEventSource = new EventSource(`/api/proxies/${rule.id}/logs/stream?tail=100`, { withCredentials: true, }) logEventSource.addEventListener('log', (event) => { diff --git a/web/vite.config.ts b/web/vite.config.ts index 1b8c1b5..6ec660b 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -5,7 +5,6 @@ import vue from '@vitejs/plugin-vue' const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8')) as { version: string } export default defineConfig({ - base: process.env.VITE_BASE_PATH || '/', plugins: [vue()], define: { __APP_VERSION__: JSON.stringify(process.env.VITE_APP_VERSION || pkg.version),