This commit is contained in:
Luís Miguel 2026-03-27 07:14:54 -03:00 committed by GitHub
commit d9d41de5dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 52 additions and 28 deletions

View File

@ -5,6 +5,7 @@ import { runBenchmarkValidator, submitBenchmarkValidator } from '#validators/ben
import { RunBenchmarkJob } from '#jobs/run_benchmark_job' import { RunBenchmarkJob } from '#jobs/run_benchmark_job'
import type { BenchmarkType } from '../../types/benchmark.js' import type { BenchmarkType } from '../../types/benchmark.js'
import { randomUUID } from 'node:crypto' import { randomUUID } from 'node:crypto'
import logger from '@adonisjs/core/services/logger'
@inject() @inject()
export default class BenchmarkController { export default class BenchmarkController {
@ -52,9 +53,10 @@ export default class BenchmarkController {
result, result,
}) })
} catch (error) { } catch (error) {
logger.error({ err: error }, '[BenchmarkController] Benchmark run failed')
return response.status(500).send({ return response.status(500).send({
success: false, success: false,
error: error.message, error: 'An internal error occurred while running the benchmark.',
}) })
} }
} }
@ -181,9 +183,10 @@ export default class BenchmarkController {
} catch (error) { } catch (error) {
// Pass through the status code from the service if available, otherwise default to 400 // Pass through the status code from the service if available, otherwise default to 400
const statusCode = (error as any).statusCode || 400 const statusCode = (error as any).statusCode || 400
logger.error({ err: error }, '[BenchmarkController] Benchmark submit failed')
return response.status(statusCode).send({ return response.status(statusCode).send({
success: false, success: false,
error: error.message, error: 'Failed to submit benchmark results.',
}) })
} }
} }

View File

@ -5,6 +5,7 @@ import { createSessionSchema, updateSessionSchema, addMessageSchema } from '#val
import KVStore from '#models/kv_store' import KVStore from '#models/kv_store'
import { SystemService } from '#services/system_service' import { SystemService } from '#services/system_service'
import { SERVICE_NAMES } from '../../constants/service_names.js' import { SERVICE_NAMES } from '../../constants/service_names.js'
import logger from '@adonisjs/core/services/logger'
@inject() @inject()
export default class ChatsController { export default class ChatsController {
@ -45,8 +46,9 @@ export default class ChatsController {
const session = await this.chatService.createSession(data.title, data.model) const session = await this.chatService.createSession(data.title, data.model)
return response.status(201).json(session) return response.status(201).json(session)
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to create session')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to create session', error: 'Failed to create session',
}) })
} }
} }
@ -56,8 +58,9 @@ export default class ChatsController {
const suggestions = await this.chatService.getChatSuggestions() const suggestions = await this.chatService.getChatSuggestions()
return response.status(200).json({ suggestions }) return response.status(200).json({ suggestions })
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to get suggestions')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to get suggestions', error: 'Failed to get suggestions',
}) })
} }
} }
@ -69,8 +72,9 @@ export default class ChatsController {
const session = await this.chatService.updateSession(sessionId, data) const session = await this.chatService.updateSession(sessionId, data)
return session return session
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to update session')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to update session', error: 'Failed to update session',
}) })
} }
} }
@ -81,8 +85,9 @@ export default class ChatsController {
await this.chatService.deleteSession(sessionId) await this.chatService.deleteSession(sessionId)
return response.status(204) return response.status(204)
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to delete session')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to delete session', error: 'Failed to delete session',
}) })
} }
} }
@ -94,8 +99,9 @@ export default class ChatsController {
const message = await this.chatService.addMessage(sessionId, data.role, data.content) const message = await this.chatService.addMessage(sessionId, data.role, data.content)
return response.status(201).json(message) return response.status(201).json(message)
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to add message')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to add message', error: 'Failed to add message',
}) })
} }
} }
@ -105,8 +111,9 @@ export default class ChatsController {
const result = await this.chatService.deleteAllSessions() const result = await this.chatService.deleteAllSessions()
return response.status(200).json(result) return response.status(200).json(result)
} catch (error) { } catch (error) {
logger.error({ err: error }, '[ChatsController] Failed to delete all sessions')
return response.status(500).json({ return response.status(500).json({
error: error instanceof Error ? error.message : 'Failed to delete all sessions', error: 'Failed to delete all sessions',
}) })
} }
} }

View File

@ -6,6 +6,7 @@ import app from '@adonisjs/core/services/app'
import { randomBytes } from 'node:crypto' import { randomBytes } from 'node:crypto'
import { sanitizeFilename } from '../utils/fs.js' import { sanitizeFilename } from '../utils/fs.js'
import { deleteFileSchema, getJobStatusSchema } from '#validators/rag' import { deleteFileSchema, getJobStatusSchema } from '#validators/rag'
import logger from '@adonisjs/core/services/logger'
@inject() @inject()
export default class RagController { export default class RagController {
@ -79,7 +80,8 @@ export default class RagController {
const syncResult = await this.ragService.scanAndSyncStorage() const syncResult = await this.ragService.scanAndSyncStorage()
return response.status(200).json(syncResult) return response.status(200).json(syncResult)
} catch (error) { } catch (error) {
return response.status(500).json({ error: 'Error scanning and syncing storage', details: error.message }) logger.error({ err: error }, '[RagController] Error scanning and syncing storage')
return response.status(500).json({ error: 'Error scanning and syncing storage' })
} }
} }
} }

View File

@ -6,6 +6,7 @@ import { CheckServiceUpdatesJob } from '#jobs/check_service_updates_job'
import { affectServiceValidator, checkLatestVersionValidator, installServiceValidator, subscribeToReleaseNotesValidator, updateServiceValidator } from '#validators/system'; import { affectServiceValidator, checkLatestVersionValidator, installServiceValidator, subscribeToReleaseNotesValidator, updateServiceValidator } from '#validators/system';
import { inject } from '@adonisjs/core' import { inject } from '@adonisjs/core'
import type { HttpContext } from '@adonisjs/core/http' import type { HttpContext } from '@adonisjs/core/http'
import logger from '@adonisjs/core/services/logger'
@inject() @inject()
export default class SystemController { export default class SystemController {
@ -144,7 +145,8 @@ export default class SystemController {
) )
response.send({ versions: updates }) response.send({ versions: updates })
} catch (error) { } catch (error) {
response.status(500).send({ error: `Failed to fetch versions: ${error.message}` }) logger.error({ err: error }, `[SystemController] Failed to fetch versions for ${serviceName}`)
response.status(500).send({ error: 'Failed to fetch available versions for this service.' })
} }
} }

View File

@ -65,7 +65,7 @@ export class CollectionUpdateService {
return { return {
updates: [], updates: [],
checked_at: new Date().toISOString(), checked_at: new Date().toISOString(),
error: `Nomad API returned status ${error.response.status}`, error: 'Failed to check for content updates. The update service may be temporarily unavailable.',
} }
} }
const message = const message =
@ -74,7 +74,7 @@ export class CollectionUpdateService {
return { return {
updates: [], updates: [],
checked_at: new Date().toISOString(), checked_at: new Date().toISOString(),
error: `Failed to contact Nomad API: ${message}`, error: 'Failed to contact the update service. Please try again later.',
} }
} }
} }

View File

@ -92,10 +92,10 @@ export class DockerService {
message: `Invalid action: ${action}. Use 'start', 'stop', or 'restart'.`, message: `Invalid action: ${action}. Use 'start', 'stop', or 'restart'.`,
} }
} catch (error) { } catch (error) {
logger.error(`Error starting service ${serviceName}: ${error.message}`) logger.error({ err: error }, `[DockerService] Error controlling service ${serviceName}`)
return { return {
success: false, success: false,
message: `Failed to start service ${serviceName}: ${error.message}`, message: `Failed to ${action} service ${serviceName}. Check server logs for details.`,
} }
} }
} }
@ -308,8 +308,8 @@ export class DockerService {
) )
} }
} catch (error) { } catch (error) {
logger.warn(`Error during container cleanup: ${error.message}`) logger.warn({ err: error }, `[DockerService] Error during container cleanup for ${serviceName}`)
this._broadcast(serviceName, 'cleanup-warning', `Warning during cleanup: ${error.message}`) this._broadcast(serviceName, 'cleanup-warning', 'Warning during container cleanup. Check server logs for details.')
} }
// Step 3: Clear volumes/data if needed // Step 3: Clear volumes/data if needed
@ -335,11 +335,11 @@ export class DockerService {
this._broadcast(serviceName, 'no-volumes', `No volumes found to clear`) this._broadcast(serviceName, 'no-volumes', `No volumes found to clear`)
} }
} catch (error) { } catch (error) {
logger.warn(`Error during volume cleanup: ${error.message}`) logger.warn({ err: error }, `[DockerService] Error during volume cleanup for ${serviceName}`)
this._broadcast( this._broadcast(
serviceName, serviceName,
'volume-cleanup-warning', 'volume-cleanup-warning',
`Warning during volume cleanup: ${error.message}` 'Warning during volume cleanup. Check server logs for details.'
) )
} }
@ -363,11 +363,11 @@ export class DockerService {
message: `Service ${serviceName} force reinstall initiated successfully. You can receive updates via server-sent events.`, message: `Service ${serviceName} force reinstall initiated successfully. You can receive updates via server-sent events.`,
} }
} catch (error) { } catch (error) {
logger.error(`Force reinstall failed for ${serviceName}: ${error.message}`) logger.error({ err: error }, `[DockerService] Force reinstall failed for ${serviceName}`)
await this._cleanupFailedInstallation(serviceName) await this._cleanupFailedInstallation(serviceName)
return { return {
success: false, success: false,
message: `Failed to force reinstall service ${serviceName}: ${error.message}`, message: `Failed to force reinstall service ${serviceName}. Check server logs for details.`,
} }
} }
} }
@ -601,10 +601,10 @@ export class DockerService {
return { success: true, message: `Service ${serviceName} container removed successfully` } return { success: true, message: `Service ${serviceName} container removed successfully` }
} catch (error) { } catch (error) {
logger.error(`Error removing service container: ${error.message}`) logger.error({ err: error }, `[DockerService] Error removing service container ${serviceName}`)
return { return {
success: false, success: false,
message: `Failed to remove service ${serviceName} container: ${error.message}`, message: `Failed to remove service ${serviceName} container. Check server logs for details.`,
} }
} }
} }
@ -1028,10 +1028,10 @@ export class DockerService {
this._broadcast( this._broadcast(
serviceName, serviceName,
'update-rollback', 'update-rollback',
`Update failed: ${error.message}` 'Update failed. Check server logs for details.'
) )
logger.error(`[DockerService] Update failed for ${serviceName}: ${error.message}`) logger.error({ err: error }, `[DockerService] Update failed for ${serviceName}`)
return { success: false, message: `Update failed: ${error.message}` } return { success: false, message: 'Update failed. Check server logs for details.' }
} }
} }

View File

@ -17,6 +17,7 @@ import { join, resolve, sep } from 'path'
import urlJoin from 'url-join' import urlJoin from 'url-join'
import { RunDownloadJob } from '#jobs/run_download_job' import { RunDownloadJob } from '#jobs/run_download_job'
import logger from '@adonisjs/core/services/logger' import logger from '@adonisjs/core/services/logger'
import { assertNotPrivateUrl } from '#validators/common'
import InstalledResource from '#models/installed_resource' import InstalledResource from '#models/installed_resource'
import { CollectionManifestService } from './collection_manifest_service.js' import { CollectionManifestService } from './collection_manifest_service.js'
import type { CollectionWithStatus, MapsSpec } from '../../types/collections.js' import type { CollectionWithStatus, MapsSpec } from '../../types/collections.js'
@ -109,6 +110,13 @@ export class MapService implements IMapService {
const downloadFilenames: string[] = [] const downloadFilenames: string[] = []
for (const resource of toDownload) { for (const resource of toDownload) {
try {
assertNotPrivateUrl(resource.url)
} catch {
logger.warn(`[MapService] Blocked download from private/loopback URL: ${resource.url}`)
continue
}
const existing = await RunDownloadJob.getByUrl(resource.url) const existing = await RunDownloadJob.getByUrl(resource.url)
if (existing) { if (existing) {
logger.warn(`[MapService] Download already in progress for URL ${resource.url}, skipping.`) logger.warn(`[MapService] Download already in progress for URL ${resource.url}, skipping.`)
@ -233,6 +241,7 @@ export class MapService implements IMapService {
url: string url: string
): Promise<{ filename: string; size: number } | { message: string }> { ): Promise<{ filename: string; size: number } | { message: string }> {
try { try {
assertNotPrivateUrl(url)
const parsed = new URL(url) const parsed = new URL(url)
if (!parsed.pathname.endsWith('.pmtiles')) { if (!parsed.pathname.endsWith('.pmtiles')) {
throw new Error(`Invalid PMTiles file URL: ${url}. URL must end with .pmtiles`) throw new Error(`Invalid PMTiles file URL: ${url}. URL must end with .pmtiles`)
@ -256,7 +265,8 @@ export class MapService implements IMapService {
return { filename, size } return { filename, size }
} catch (error: any) { } catch (error: any) {
return { message: `Preflight check failed: ${error.message}` } logger.error({ err: error }, '[MapService] Preflight check failed for URL')
return { message: 'Preflight check failed. Please verify the URL is valid and accessible.' }
} }
} }

View File

@ -47,10 +47,10 @@ export class SystemUpdateService {
message: 'System update initiated. The admin container will restart during the process.', message: 'System update initiated. The admin container will restart during the process.',
} }
} catch (error) { } catch (error) {
logger.error('[SystemUpdateService]: Failed to request system update:', error) logger.error({ err: error }, '[SystemUpdateService] Failed to request system update')
return { return {
success: false, success: false,
message: `Failed to request update: ${error.message}`, message: 'Failed to request system update. Check server logs for details.',
} }
} }
} }