import { MeiliSearch } from 'meilisearch'; import slugify from 'slugify'; const { platform } = require('os'); const path = require('path'); const spawn = require('child_process').spawn; class MeilisearchService { private client: MeiliSearch; private binaryPath: string; private serverProcess: any | null = null; constructor() { this.client = new MeiliSearch({ host: 'http://localhost:7700', }); this.binaryPath = this.getBinaryPath(); } private getBinaryPath(): string { const arch = process.arch; let binaryName: string; switch (platform()) { case 'darwin': binaryName = arch === 'arm64' ? 'meilisearch-macos-arm' : 'meilisearch-macos-x64'; break; case 'win32': binaryName = 'meilisearch-windows.exe'; break; case 'linux': binaryName = arch === 'arm' ? 'meilisearch-linux-arm' : 'meilisearch-linux-x64'; break; default: throw new Error(`Unsupported platform: ${platform()}`); } return path.join(__dirname, '..', 'meilisearch_binaries', binaryName); } public async startServer(): Promise { if (this.serverProcess) { console.log('Meilisearch server is already running.'); return; } try { const apiKey = 'Damie'; // Use the system's name as the API key process.env.MEILISEARCH_MASTER_KEY = apiKey; this.serverProcess = spawn(this.binaryPath, ['--http-addr', '127.0.0.1:7700'], { env: process.env, // Pass the environment variables to the child process }); this.serverProcess.stdout?.on('data', (data) => { console.log(`Meilisearch: ${data}`); }); this.serverProcess.stderr?.on('data', (data) => { console.error(`Meilisearch: ${data}`); }); this.serverProcess.on('close', (code) => { console.log(`Meilisearch server stopped with code ${code}`); this.serverProcess = null; }); this.serverProcess.on('error', (err) => { console.error('Failed to start Meilisearch server:', err); this.serverProcess = null; }); console.log('Meilisearch server started.'); } catch (error) { console.error('Failed to start Meilisearch server:', error); } } public async stopServer(): Promise { if (!this.serverProcess) { console.log('Meilisearch server is not running.'); return; } this.serverProcess.kill(); this.serverProcess = null; console.log('Meilisearch server stopped.'); } // Implement methods for adding, removing, and updating documents and collections // using the Meilisearch API. public async addDocuments(indexName: string, documents: any[]): Promise { try { const index = this.client.index(indexName) await index.addDocuments(documents) console.log(`Added ${documents.length} documents to index ${indexName}`); } catch (error) { console.error(`Failed to add documents to index ${indexName}:`, error); throw error; } } public async removeDocuments(indexName: string, documentIds: string[]): Promise { try { const index = this.client.index(indexName) await index.deleteDocuments(documentIds) console.log(`Removed documents with IDs ${documentIds.join(',')} from index ${indexName}`); } catch (error) { console.error(`Failed to remove documents from index ${indexName}:`, error); throw error; } } public async updateDocuments(indexName: string, documents: any[]): Promise { try { const index = this.client.index(indexName) await index.updateDocuments(documents) console.log(`Updated ${documents.length} documents in index ${indexName}`); } catch (error) { console.error(`Failed to update documents in index ${indexName}:`, error); throw error; } } public async deleteIndex(indexName: string): Promise { try { await this.client.deleteIndex(indexName); console.log(`Deleted index ${indexName}`); } catch (error) { console.error(`Failed to delete index ${indexName}:`, error); throw error; } } public async createIndex(indexName: string): Promise { try { await this.client.createIndex(indexName); console.log(`Created index ${indexName}`); } catch (error) { console.error(`Failed to create index ${indexName}:`, error); throw error; } } public async getDocuments(indexName: string): Promise { try { const index = this.client.index(indexName); const documents = await index.getDocuments(); return documents.results; } catch (error) { console.error(`Failed to get documents from index ${indexName}:`, error); throw error; } } private slugifyPath(path):string { return path .toLowerCase() // Convert to lowercase .replace(/[\\\/:*?"<>|]/g, '-') // Replace invalid characters with a dash .replace(/\s+/g, '-') // Replace spaces with a dash .replace(/-+/g, '-') // Replace multiple dashes with a single dash .replace(/^-+|-+$/g, ''); } public async search(indexName: string, query: string): Promise { try { console.log(indexName) const index = this.client.index(this.slugifyPath(indexName)); const { hits } = await index.search(query); return hits; } catch (error) { console.error(`Failed to search index ${indexName} with query ${query}:`, error); throw error; } } } export default MeilisearchService;