# Индексация проектов в Solver SDK

Данный документ описывает процесс индексации проектов через SDK и отслеживания этого процесса с помощью WebSocket соединений.

## Содержание

- [Введение](#введение)
- [API для индексации](#api-для-индексации)
- [Инкрементальная индексация](#инкрементальная-индексация)
- [Отслеживание процесса индексации](#отслеживание-процесса-индексации)
- [События WebSocket](#события-websocket)
- [Обработка ошибок](#обработка-ошибок)
- [Примеры использования](#примеры-использования)

## Введение

Индексация проекта - это процесс сканирования и анализа файлов проекта для дальнейшего поиска и обработки информации. Solver SDK предоставляет набор методов для управления индексацией проектов и отслеживания этого процесса.

## API для индексации

### Основные методы

| Метод | Описание |
|-------|----------|
| `sdk.projects.indexProject(projectId, options)` | Запускает индексацию проекта |
| `sdk.projects.stopIndexing(projectId)` | Останавливает индексацию проекта |
| `sdk.projects.getIndexingStatus(projectId)` | Получает текущий статус индексации |
| `sdk.projects.updateFileIndex(projectId, filePath, options)` | Обновляет индекс конкретного файла |

### Пример использования API

```javascript
// Запуск индексации
const result = await sdk.projects.indexProject(projectId, {
  forceFull: false, // true для принудительной полной переиндексации
  includePatterns: ['**/*.js', '**/*.ts'], // glob паттерны для включения файлов
  excludePatterns: ['**/node_modules/**'] // glob паттерны для исключения файлов
});
console.log('Индексация запущена. Задача:', result.taskId);

// Получение статуса индексации
const status = await sdk.projects.getIndexingStatus(projectId);
console.log(`Статус: ${status.status}, прогресс: ${status.progress}%`);

// Остановка индексации
await sdk.projects.stopIndexing(projectId);
console.log('Индексация остановлена');
```

## Инкрементальная индексация

В SDK версии 1.7.2 добавлена поддержка инкрементальной индексации отдельных файлов, что позволяет обновлять только изменившиеся файлы без необходимости переиндексации всего проекта.

### Обновление индекса отдельного файла

```javascript
// Обновление индекса файла с передачей содержимого
const result = await sdk.projects.updateFileIndex(
  projectId,
  'src/components/App.js',
  {
    content: 'console.log("Hello World");', // содержимое файла
    force: false // true для принудительного обновления
  }
);

console.log(`Файл ${result.filePath} успешно проиндексирован`);
console.log(`Метаданные файла:`, result.fileIndex);

// Альтернативный вариант через ContextApi
await sdk.context.updateFileIndex(
  projectId,
  'src/components/App.js',
  'console.log("Hello World");',
  false // force flag
);
```

### Инкрементальная индексация из файловой системы

```javascript
// Обновление индекса без передачи содержимого
// SDK прочитает файл с диска
const result = await sdk.projects.updateFileIndex(projectId, 'src/components/App.js');

console.log(`Файл ${result.filePath} успешно проиндексирован`);
```

### Пакетное обновление нескольких файлов

```javascript
// Обновление нескольких файлов
const filesToUpdate = [
  { path: 'src/components/App.js' },
  { path: 'src/utils/helpers.js', content: 'export function helper() {}' }
];

const results = await Promise.all(
  filesToUpdate.map(file => 
    sdk.projects.updateFileIndex(projectId, file.path, { content: file.content })
  )
);

console.log(`Обновлено ${results.length} файлов`);
```

## Отслеживание процесса индексации

Для отслеживания процесса индексации в реальном времени используется WebSocket соединение. SDK предоставляет методы для подключения к серверу и получения событий о ходе индексации.

### Подключение к WebSocket (версия 1.7.2)

```javascript
// Прямое подключение к пространству имен индексации
await sdk.projects.connectWebSocket();

// Проверка подключения
if (sdk.projects.isWebSocketConnected()) {
  console.log('Успешно подключено к WebSocket серверу');
} else {
  console.error('Не удалось подключиться к WebSocket серверу');
}
```

### Установка обработчиков событий

```javascript
// Установка обработчиков событий
sdk.projects.on('indexing_start', (data) => {
  console.log(`Индексация началась для проекта: ${data.projectId}`);
});

sdk.projects.on('indexing_progress', (data) => {
  console.log(`Прогресс: ${data.progress}% (${data.indexedFiles}/${data.totalFiles} файлов)`);
});

sdk.projects.on('indexing_complete', (data) => {
  console.log(`Индексация завершена! Проиндексировано ${data.indexedFiles} файлов`);
});

sdk.projects.on('indexing_error', (data) => {
  console.error(`Ошибка индексации: ${data.message}`);
});

sdk.projects.on('file_indexed', (data) => {
  console.log(`Файл проиндексирован: ${data.filePath}`);
});

sdk.projects.on('error', (error) => {
  console.error(`Ошибка WebSocket: ${error.message}`);
});
```

### Отключение от WebSocket

```javascript
// Отключение от пространства имен индексации
await sdk.projects.disconnectWebSocket();

// Или через WebSocketClient
const wsClient = sdk.getWebSocketClient();
await wsClient.disconnect(WebSocketNamespace.INDEXING);

// Отключение от всех пространств имен
await wsClient.disconnectAll();
```

## События WebSocket

При индексации проектов сервер отправляет следующие типы событий:

| Событие | Описание | Данные |
|---------|----------|--------|
| `indexing_start` | Начало процесса индексации | `{ projectId: string }` |
| `indexing_progress` | Обновление прогресса индексации | `{ projectId: string, totalFiles: number, indexedFiles: number, progress: number, startTime: string, elapsedTime: number, estimatedTimeRemaining?: number }` |
| `indexing_complete` | Завершение индексации | `{ projectId: string, totalFiles: number, indexedFiles: number, skippedFiles: number, startTime: string, endTime: string, totalTime: number }` |
| `indexing_error` | Ошибка при индексации | `{ projectId: string, message: string, code?: string, details?: any }` |
| `file_indexed` | Отдельный файл проиндексирован | `{ projectId: string, filePath: string, fileIndex: object }` |
| `file_index_error` | Ошибка при индексации файла | `{ projectId: string, filePath: string, message: string }` |

## Обработка ошибок

При работе с индексацией могут возникать различные ошибки. Вот типичные ошибки и способы их обработки:

### Ошибки HTTP API

```javascript
try {
  await sdk.projects.indexProject(projectId);
} catch (error) {
  if (error.status === 404) {
    console.error('Проект не найден');
  } else if (error.status === 409) {
    console.error('Индексация уже запущена для этого проекта');
  } else {
    console.error('Неизвестная ошибка:', error.message);
  }
}
```

### Ошибки WebSocket

```javascript
// Подключение с обработкой ошибок
try {
  await sdk.projects.connectWebSocket();
} catch (error) {
  console.error('Ошибка подключения WebSocket:', error);
}

// Обработчик ошибок WebSocket
sdk.projects.on('error', (error) => {
  console.error('Ошибка WebSocket:', error);
});

// Обработка отключения
sdk.projects.on('disconnect', () => {
  console.log('WebSocket соединение прервано');
  
  // Автоматическое переподключение
  setTimeout(async () => {
    try {
      await sdk.projects.connectWebSocket();
      console.log('Переподключено к WebSocket');
    } catch (error) {
      console.error('Не удалось переподключиться:', error);
    }
  }, 3000);
});
```

## Примеры использования

### Базовый пример индексации

```javascript
// Инициализация SDK
const sdk = new CodeSolverSDK({
  baseURL: 'https://localhost:3000',
  apiKey: 'your-api-key',
  websocket: {
    reconnect: true // Автоматическое переподключение
  }
});

// Запуск индексации
async function indexProject(projectId) {
  try {
    // Подключаемся к WebSocket пространству имен индексации
    await sdk.projects.connectWebSocket();
    
    // Устанавливаем обработчики событий
    sdk.projects.on('indexing_progress', (data) => {
      console.log(`Прогресс: ${data.progress}%`);
    });
    
    sdk.projects.on('indexing_complete', (data) => {
      console.log('Индексация завершена!');
    });
    
    // Запускаем индексацию
    const result = await sdk.projects.indexProject(projectId);
    console.log('Индексация запущена:', result);
    
    // Ждем завершения индексации
    return new Promise((resolve, reject) => {
      sdk.projects.on('indexing_complete', (data) => {
        sdk.projects.disconnectWebSocket();
        resolve(data);
      });
      
      sdk.projects.on('indexing_error', (error) => {
        sdk.projects.disconnectWebSocket();
        reject(new Error(error.message));
      });
      
      // Таймаут на случай, если что-то пойдет не так
      setTimeout(() => {
        sdk.projects.disconnectWebSocket();
        reject(new Error('Таймаут индексации'));
      }, 120000); // 2 минуты
    });
  } catch (error) {
    console.error('Ошибка индексации:', error);
    throw error;
  }
}
```

### Пример с отображением прогресс-бара

```javascript
const progressBar = require('progress');

async function indexWithProgressBar(projectId) {
  // Создаем прогресс-бар
  let bar = null;
  
  // Подключаемся к WebSocket
  await sdk.projects.connectWebSocket();
  
  // Устанавливаем обработчики событий
  sdk.projects.on('indexing_start', () => {
    console.log('Индексация началась...');
  });
  
  sdk.projects.on('indexing_progress', (data) => {
    if (!bar) {
      bar = new progressBar('Индексация [:bar] :percent :etas', {
        complete: '=',
        incomplete: ' ',
        width: 50,
        total: 100
      });
    }
    
    bar.update(data.progress / 100);
  });
  
  sdk.projects.on('indexing_complete', (data) => {
    if (bar) {
      bar.update(1.0); // Заполняем прогресс-бар
    }
    console.log(`\nИндексация завершена! Обработано ${data.indexedFiles} файлов за ${data.totalTime.toFixed(2)} секунд`);
  });
  
  // Запускаем индексацию
  await sdk.projects.indexProject(projectId);
  
  // Возвращаем Promise, который разрешится при завершении индексации
  return new Promise((resolve, reject) => {
    sdk.projects.on('indexing_complete', (data) => {
      sdk.projects.disconnectWebSocket();
      resolve(data);
    });
    
    sdk.projects.on('indexing_error', (error) => {
      sdk.projects.disconnectWebSocket();
      reject(new Error(error.message));
    });
  });
}
```

### Инкрементальное обновление файлов при изменении

```javascript
const fs = require('fs');
const path = require('path');
const chokidar = require('chokidar');

// Функция для наблюдения за изменениями в директории и инкрементальной индексации
async function watchAndIndex(projectId, dirPath) {
  // Подключение WebSocket для получения уведомлений о индексации
  await sdk.projects.connectWebSocket();
  
  // Устанавливаем обработчики для отдельных файлов
  sdk.projects.on('file_indexed', (data) => {
    console.log(`Файл проиндексирован: ${data.filePath}`);
  });
  
  sdk.projects.on('file_index_error', (data) => {
    console.error(`Ошибка индексации файла ${data.filePath}: ${data.message}`);
  });
  
  // Создаем наблюдателя за файловой системой
  const watcher = chokidar.watch(dirPath, {
    ignored: /(^|[\/\\])\../, // Игнорировать скрытые файлы
    persistent: true,
    ignoreInitial: true
  });
  
  // При изменении файла, обновляем его индекс
  watcher.on('change', async (filePath) => {
    try {
      // Получаем путь относительно корня проекта
      const relPath = path.relative(dirPath, filePath);
      
      console.log(`Файл изменился: ${relPath}`);
      
      // Обновляем индекс файла
      await sdk.projects.updateFileIndex(projectId, relPath);
      
      console.log(`Отправлен запрос на обновление индекса файла: ${relPath}`);
    } catch (error) {
      console.error(`Ошибка обновления индекса: ${error.message}`);
    }
  });
  
  console.log(`Наблюдение за директорией ${dirPath} началось`);
  
  // Возвращаем функцию для остановки наблюдения
  return () => {
    watcher.close();
    sdk.projects.disconnectWebSocket();
    console.log('Наблюдение остановлено');
  };
}
```

Дополнительные примеры использования API индексации можно найти в файле `solver-sdk/examples/indexing-example.js`. 