diff --git a/.gitignore b/.gitignore index 3d4574c5..39446496 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ coverage api/oracle-cloud/build api/fetch_cache api/postgres_db +api/meilisearch_db api/nodemon.json # web diff --git a/README.md b/README.md index 1ca2c49b..d49b845c 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ npm run dev:all - For api server go to - For web server go to +- For search server go to **Note** diff --git a/api/docker-compose.yml b/api/docker-compose.yml index 5608a938..f14e426a 100644 --- a/api/docker-compose.yml +++ b/api/docker-compose.yml @@ -15,7 +15,7 @@ services: ports: - "7700:7700" volumes: - - ./meilisearch_db:/data.ms + - ./meilisearch_db:/meili_data environment: MEILI_NO_ANALYTICS: true MEILI_MASTER_KEY: "default" diff --git a/api/oracle-cloud/docker-compose.yml b/api/oracle-cloud/docker-compose.yml index 9dbc5577..a285e7d0 100644 --- a/api/oracle-cloud/docker-compose.yml +++ b/api/oracle-cloud/docker-compose.yml @@ -27,3 +27,12 @@ services: environment: POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_DB: db + meilisearch: + image: getmeili/meilisearch:latest + ports: + - "7700:7700" + volumes: + - /home/ubuntu/app-data/api/meilisearch_db:/meili_data + environment: + MEILI_NO_ANALYTICS: true + MEILI_MASTER_KEY: "default" diff --git a/api/package.json b/api/package.json index 06686b19..d5a192e2 100644 --- a/api/package.json +++ b/api/package.json @@ -77,7 +77,7 @@ "lint:prettier": "prettier --config ../packages/tooling/.prettierrc --ignore-path ../packages/tooling/.prettierignore --log-level warn", "lint:ts-prune": "tsx ../packages/tooling/setup-ts-prune.ts && ts-prune --error", "lint:tsc": "tspc --noEmit", - "start": "wait-port postgres:5432 && delay 2 && node dist/app/index.js", + "start": "wait-port postgres:5432 && wait-port meilisearch:7700 && delay 2 && node dist/app/index.js", "start:dev": "tsx ../packages/tooling/nodemon.ts \"@dzcode.io/api\" && npm-run-all --parallel start:nodemon db:server", "start:nodemon": "wait-port localhost:5432 && delay 2 && nodemon dist/app/index.js", "test": "npm run build && npm run test:alone", diff --git a/api/src/app/index.ts b/api/src/app/index.ts index b6b0a15b..5af6505e 100644 --- a/api/src/app/index.ts +++ b/api/src/app/index.ts @@ -25,6 +25,7 @@ import { PostgresService } from "src/postgres/service"; import { ProjectController } from "src/project/controller"; import { RobotsController } from "./middlewares/robots"; import { SearchController } from "src/search/controller"; +import { SearchService } from "src/search/service"; import { SecurityMiddleware } from "./middlewares/security"; import { fsConfig } from "@dzcode.io/utils/dist/config"; @@ -38,6 +39,10 @@ useContainer(Container); // eslint-disable-line react-hooks/rules-of-hooks const { NODE_ENV, PORT } = Container.get(ConfigService).env(); + // Initialize Search Service + const searchService = Container.get(SearchService); + await searchService.ensureIndexes(); + // Add crons to DI container const CronServices = [DigestCron]; CronServices.forEach((service) => Container.get(service)); diff --git a/api/src/search/service.ts b/api/src/search/service.ts index 332fd4d2..4ac9436e 100644 --- a/api/src/search/service.ts +++ b/api/src/search/service.ts @@ -1,7 +1,8 @@ +import { SearchItem, SearchType } from "./types"; + import { ConfigService } from "src/config/service"; import { LoggerService } from "src/logger/service"; import { MeiliSearch } from "meilisearch"; -import { SearchItem } from "./types"; import { Service } from "typedi"; @Service() @@ -11,6 +12,7 @@ export class SearchService { private readonly configService: ConfigService, private readonly logger: LoggerService, ) { + this.logger.info({ message: "Initializing MeiliSearch client" }); const { MEILISEARCH_URL, MEILISEARCH_MASTER_KEY } = this.configService.env(); @@ -18,10 +20,37 @@ export class SearchService { host: MEILISEARCH_URL, apiKey: MEILISEARCH_MASTER_KEY, }); + this.logger.info({ + message: `MeiliSearch client initialized with url ${MEILISEARCH_URL}`, + }); } public search = async (query: string): Promise => { this.logger.info({ message: `Searching for ${query}` }); return []; }; + + public index = async ( + index: SearchType, + data: SearchItem[], + ): Promise => { + this.logger.info({ + message: `Indexing ${data.length} items in ${index}`, + }); + await this.meilisearch.index(index).addDocuments(data); + this.logger.info({ + message: `Indexed ${data.length} items in ${index}`, + }); + }; + + public ensureIndexes = async (): Promise => { + await this.meilisearch.createIndex("project"); + this.logger.info({ message: "project index created" }); + + await this.meilisearch.createIndex("contribution"); + this.logger.info({ message: "contribution index created" }); + + await this.meilisearch.createIndex("contributor"); + this.logger.info({ message: "contributor index created" }); + }; } diff --git a/api/src/search/types.ts b/api/src/search/types.ts index 0643ebab..4c34e538 100644 --- a/api/src/search/types.ts +++ b/api/src/search/types.ts @@ -10,4 +10,4 @@ export interface SearchItem { type: SearchType; } -type SearchType = "project" | "contribution" | "contributor"; +export type SearchType = "project" | "contribution" | "contributor";