Newer
Older
hard-panel / panel / frontend / src / api.js
// API-клиент панели. Админ-токен = единственный секрет, храним в localStorage
// (это личная панель; JWT-сессии появятся, если понадобится мультипользовательность).

const TOKEN_KEY = 'ghard_admin_token'

export function getToken() {
  return localStorage.getItem(TOKEN_KEY) || ''
}

export function setToken(token) {
  localStorage.setItem(TOKEN_KEY, token)
}

export function clearToken() {
  localStorage.removeItem(TOKEN_KEY)
}

export class ApiError extends Error {
  constructor(status, message) {
    super(message)
    this.status = status
  }
}

async function request(path, { method = 'GET', body } = {}) {
  const token = getToken()
  if (!token && path !== '/auth/check') {
    throw new ApiError(401, 'нет токена')
  }
  const response = await fetch('/api/v1' + path, {
    method,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
  })
  if (response.status === 401) {
    clearToken()
    if (location.pathname !== '/login') location.href = '/login'
    throw new ApiError(401, 'невалидный токен')
  }
  if (!response.ok) {
    let detail = response.statusText
    try {
      const data = await response.json()
      detail = data.detail || detail
    } catch { /* не-JSON ответ */ }
    throw new ApiError(response.status, detail)
  }
  if (response.status === 204) return null
  return response.json()
}

export const api = {
  // проверка, что токен живой (401 внутри request сам выкинет на /login)
  check: () => request('/servers').then(() => true).catch(() => false),

  servers: () => request('/servers'),
  server: (id) => request(`/servers/${id}`),
  createServer: (name, hostname = '', interval = 30) =>
    request('/servers', { method: 'POST', body: { name, hostname, interval } }),
  updateServer: (id, fields) =>
    request(`/servers/${id}`, { method: 'PATCH', body: fields }),
  deleteServer: (id) => request(`/servers/${id}`, { method: 'DELETE' }),
  metrics: (id, since, until, limit = 1000) => {
    const params = new URLSearchParams()
    if (since) params.set('since', since.toISOString())
    if (until) params.set('until', until.toISOString())
    params.set('limit', String(limit))
    return request(`/servers/${id}/metrics?${params}`)
  },
}