2025-02-09 03:10:26 -05:00
|
|
|
import { MeiliSearch } from 'meilisearch';
|
|
|
|
import slugify from 'slugify';
|
|
|
|
const { platform } = require('os');
|
|
|
|
const path = require('path');
|
|
|
|
const spawn = require('child_process').spawn;
|
2025-02-09 02:09:16 -05:00
|
|
|
|
|
|
|
class MeilisearchService {
|
|
|
|
private client: MeiliSearch;
|
2025-02-09 03:10:26 -05:00
|
|
|
private binaryPath: string;
|
|
|
|
private serverProcess: any | null = null;
|
2025-02-09 02:09:16 -05:00
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.client = new MeiliSearch({
|
|
|
|
host: 'http://localhost:7700',
|
|
|
|
});
|
2025-02-09 03:10:26 -05:00
|
|
|
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<void> {
|
|
|
|
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<void> {
|
|
|
|
if (!this.serverProcess) {
|
|
|
|
console.log('Meilisearch server is not running.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.serverProcess.kill();
|
|
|
|
this.serverProcess = null;
|
|
|
|
console.log('Meilisearch server stopped.');
|
2025-02-09 02:09:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Implement methods for adding, removing, and updating documents and collections
|
|
|
|
// using the Meilisearch API.
|
|
|
|
public async addDocuments(indexName: string, documents: any[]): Promise<void> {
|
|
|
|
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<void> {
|
|
|
|
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<void> {
|
|
|
|
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<void> {
|
|
|
|
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<void> {
|
|
|
|
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<any[]> {
|
|
|
|
try {
|
|
|
|
const index = this.client.index(indexName);
|
2025-02-09 03:10:26 -05:00
|
|
|
const documents = await index.getDocuments();
|
|
|
|
return documents.results;
|
2025-02-09 02:09:16 -05:00
|
|
|
} catch (error) {
|
|
|
|
console.error(`Failed to get documents from index ${indexName}:`, error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
2025-02-09 03:10:26 -05:00
|
|
|
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, '');
|
|
|
|
}
|
2025-02-09 02:09:16 -05:00
|
|
|
|
|
|
|
public async search(indexName: string, query: string): Promise<any[]> {
|
|
|
|
try {
|
2025-02-09 03:10:26 -05:00
|
|
|
console.log(indexName)
|
|
|
|
const index = this.client.index(this.slugifyPath(indexName));
|
2025-02-09 02:09:16 -05:00
|
|
|
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;
|