171 lines
4.6 KiB
Go
171 lines
4.6 KiB
Go
package meiliService
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.ma-al.com/goc_daniel/b2b/app/repos/productDescriptionRepo"
|
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
|
"github.com/meilisearch/meilisearch-go"
|
|
)
|
|
|
|
type MeiliService struct {
|
|
productDescriptionRepo productDescriptionRepo.UIProductDescriptionRepo
|
|
meiliClient meilisearch.ServiceManager
|
|
}
|
|
|
|
func New() *MeiliService {
|
|
meiliURL := os.Getenv("MEILISEARCH_URL")
|
|
meiliAPIKey := os.Getenv("MEILISEARCH_API_KEY")
|
|
|
|
client := meilisearch.New(
|
|
meiliURL,
|
|
meilisearch.WithAPIKey(meiliAPIKey),
|
|
)
|
|
|
|
return &MeiliService{
|
|
meiliClient: client,
|
|
productDescriptionRepo: productDescriptionRepo.New(),
|
|
}
|
|
}
|
|
|
|
// ==================================== FOR SUPERADMIN ONLY ====================================
|
|
func (s *MeiliService) CreateIndex(id_lang uint) error {
|
|
products, err := s.productDescriptionRepo.GetMeiliProducts(id_lang)
|
|
|
|
for i := 0; i < len(products); i++ {
|
|
products[i].Description, err = cleanHTML(products[i].Description)
|
|
if err != nil {
|
|
fmt.Printf("products[i].Description: %v\n", products[i].Description)
|
|
fmt.Printf("products[i].ProductID: %v\n", products[i].ProductID)
|
|
fmt.Println("failed at description")
|
|
fmt.Printf("err: %v\n", err)
|
|
return err
|
|
}
|
|
|
|
products[i].DescriptionShort, err = cleanHTML(products[i].DescriptionShort)
|
|
if err != nil {
|
|
fmt.Printf("products[i].DescriptionShort: %v\n", products[i].DescriptionShort)
|
|
fmt.Printf("products[i].ProductID: %v\n", products[i].ProductID)
|
|
fmt.Println("failed at description short")
|
|
fmt.Printf("err: %v\n", err)
|
|
return err
|
|
}
|
|
|
|
products[i].Usage, err = cleanHTML(products[i].Usage)
|
|
if err != nil {
|
|
fmt.Printf("products[i].Usage: %v\n", products[i].Usage)
|
|
fmt.Printf("products[i].ProductID: %v\n", products[i].ProductID)
|
|
fmt.Println("failed at usage")
|
|
fmt.Printf("err: %v\n", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
primaryKey := "ProductID"
|
|
docOptions := &meilisearch.DocumentOptions{
|
|
PrimaryKey: &primaryKey,
|
|
SkipCreation: false,
|
|
}
|
|
|
|
task, err := s.meiliClient.Index(indexName).AddDocuments(products, docOptions)
|
|
if err != nil {
|
|
return fmt.Errorf("meili AddDocuments error: %w", err)
|
|
}
|
|
|
|
finishedTask, err := s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond)
|
|
fmt.Printf("Task status: %s\n", finishedTask.Status)
|
|
fmt.Printf("Task error: %s\n", finishedTask.Error)
|
|
|
|
return err
|
|
}
|
|
|
|
// ==================================== FOR DEBUG ONLY ====================================
|
|
func (s *MeiliService) Test(id_lang uint) (meilisearch.SearchResponse, error) {
|
|
indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10)
|
|
|
|
searchReq := &meilisearch.SearchRequest{
|
|
Limit: 3,
|
|
}
|
|
|
|
// Perform search
|
|
results, err := s.meiliClient.Index(indexName).Search("walek", searchReq)
|
|
if err != nil {
|
|
fmt.Printf("Meilisearch error: %v\n", err)
|
|
return meilisearch.SearchResponse{}, err
|
|
}
|
|
|
|
fmt.Printf("Search results for query 'walek' in %s: %d hits\n", indexName, len(results.Hits))
|
|
|
|
return *results, nil
|
|
}
|
|
|
|
// Search performs a full-text search on the specified index
|
|
func (s *MeiliService) Search(indexName string, query string, limit int) (meilisearch.SearchResponse, error) {
|
|
searchReq := &meilisearch.SearchRequest{
|
|
Limit: int64(limit),
|
|
}
|
|
|
|
results, err := s.meiliClient.Index(indexName).Search(query, searchReq)
|
|
if err != nil {
|
|
fmt.Printf("Meilisearch search error: %v\n", err)
|
|
return meilisearch.SearchResponse{}, err
|
|
}
|
|
|
|
return *results, nil
|
|
}
|
|
|
|
// HealthCheck checks if Meilisearch is healthy and accessible
|
|
func (s *MeiliService) HealthCheck() (*meilisearch.Health, error) {
|
|
health, err := s.meiliClient.Health()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("meilisearch health check failed: %w", err)
|
|
}
|
|
|
|
return health, nil
|
|
}
|
|
|
|
// remove all tags from HTML text
|
|
func cleanHTML(s string) (string, error) {
|
|
r := strings.NewReader(s)
|
|
d := xml.NewDecoder(r)
|
|
|
|
text := ""
|
|
|
|
// Configure the decoder for HTML; leave off strict and autoclose for XHTML
|
|
d.Strict = true
|
|
d.AutoClose = xml.HTMLAutoClose
|
|
d.Entity = xml.HTMLEntity
|
|
for {
|
|
token, err := d.Token()
|
|
if err == io.EOF {
|
|
break
|
|
} else if err != nil {
|
|
return text, err
|
|
}
|
|
|
|
switch v := token.(type) {
|
|
case xml.StartElement:
|
|
if len(text) > 0 && text[len(text)-1] != '\n' {
|
|
text += " \n "
|
|
}
|
|
case xml.EndElement:
|
|
case xml.CharData:
|
|
if strings.TrimSpace(string(v)) != "" {
|
|
text += string(v)
|
|
}
|
|
case xml.Comment:
|
|
case xml.ProcInst:
|
|
case xml.Directive:
|
|
}
|
|
}
|
|
|
|
return text, nil
|
|
}
|