717 lines
21 KiB
Go
717 lines
21 KiB
Go
package meilisearch
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v4"
|
|
)
|
|
|
|
type meilisearch struct {
|
|
client *client
|
|
}
|
|
|
|
// New create new service manager for operating on meilisearch
|
|
func New(host string, options ...Option) ServiceManager {
|
|
defOpt := defaultMeiliOpt
|
|
|
|
for _, opt := range options {
|
|
opt(defOpt)
|
|
}
|
|
|
|
return &meilisearch{
|
|
client: newClient(
|
|
defOpt.client,
|
|
host,
|
|
defOpt.apiKey,
|
|
clientConfig{
|
|
contentEncoding: defOpt.contentEncoding.encodingType,
|
|
encodingCompressionLevel: defOpt.contentEncoding.level,
|
|
disableRetry: defOpt.disableRetry,
|
|
retryOnStatus: defOpt.retryOnStatus,
|
|
maxRetries: defOpt.maxRetries,
|
|
},
|
|
),
|
|
}
|
|
}
|
|
|
|
// Connect create service manager and check connection with meilisearch
|
|
func Connect(host string, options ...Option) (ServiceManager, error) {
|
|
meili := New(host, options...)
|
|
|
|
if !meili.IsHealthy() {
|
|
return nil, ErrConnectingFailed
|
|
}
|
|
|
|
return meili, nil
|
|
}
|
|
|
|
func (m *meilisearch) ServiceReader() ServiceReader {
|
|
return m
|
|
}
|
|
|
|
func (m *meilisearch) TaskManager() TaskManager {
|
|
return m
|
|
}
|
|
|
|
func (m *meilisearch) TaskReader() TaskReader {
|
|
return m
|
|
}
|
|
|
|
func (m *meilisearch) KeyManager() KeyManager {
|
|
return m
|
|
}
|
|
|
|
func (m *meilisearch) KeyReader() KeyReader {
|
|
return m
|
|
}
|
|
|
|
func (m *meilisearch) Index(uid string) IndexManager {
|
|
return newIndex(m.client, uid)
|
|
}
|
|
|
|
func (m *meilisearch) GetIndex(indexID string) (*IndexResult, error) {
|
|
return m.GetIndexWithContext(context.Background(), indexID)
|
|
}
|
|
|
|
func (m *meilisearch) GetIndexWithContext(ctx context.Context, indexID string) (*IndexResult, error) {
|
|
return newIndex(m.client, indexID).FetchInfoWithContext(ctx)
|
|
}
|
|
|
|
func (m *meilisearch) GetRawIndex(uid string) (map[string]interface{}, error) {
|
|
return m.GetRawIndexWithContext(context.Background(), uid)
|
|
}
|
|
|
|
func (m *meilisearch) GetRawIndexWithContext(ctx context.Context, uid string) (map[string]interface{}, error) {
|
|
resp := map[string]interface{}{}
|
|
req := &internalRequest{
|
|
endpoint: "/indexes/" + uid,
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetRawIndex",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) ListIndexes(param *IndexesQuery) (*IndexesResults, error) {
|
|
return m.ListIndexesWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) ListIndexesWithContext(ctx context.Context, param *IndexesQuery) (*IndexesResults, error) {
|
|
resp := new(IndexesResults)
|
|
req := &internalRequest{
|
|
endpoint: "/indexes",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetIndexes",
|
|
}
|
|
if param != nil && param.Limit != 0 {
|
|
req.withQueryParams["limit"] = strconv.FormatInt(param.Limit, 10)
|
|
}
|
|
if param != nil && param.Offset != 0 {
|
|
req.withQueryParams["offset"] = strconv.FormatInt(param.Offset, 10)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := range resp.Results {
|
|
resp.Results[i].IndexManager = newIndex(m.client, resp.Results[i].UID)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) GetRawIndexes(param *IndexesQuery) (map[string]interface{}, error) {
|
|
return m.GetRawIndexesWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) GetRawIndexesWithContext(ctx context.Context, param *IndexesQuery) (map[string]interface{}, error) {
|
|
resp := map[string]interface{}{}
|
|
req := &internalRequest{
|
|
endpoint: "/indexes",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetRawIndexes",
|
|
}
|
|
if param != nil && param.Limit != 0 {
|
|
req.withQueryParams["limit"] = strconv.FormatInt(param.Limit, 10)
|
|
}
|
|
if param != nil && param.Offset != 0 {
|
|
req.withQueryParams["offset"] = strconv.FormatInt(param.Offset, 10)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) CreateIndex(config *IndexConfig) (*TaskInfo, error) {
|
|
return m.CreateIndexWithContext(context.Background(), config)
|
|
}
|
|
|
|
func (m *meilisearch) CreateIndexWithContext(ctx context.Context, config *IndexConfig) (*TaskInfo, error) {
|
|
request := &CreateIndexRequest{
|
|
UID: config.Uid,
|
|
PrimaryKey: config.PrimaryKey,
|
|
}
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/indexes",
|
|
method: http.MethodPost,
|
|
contentType: contentTypeJSON,
|
|
withRequest: request,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusAccepted},
|
|
functionName: "CreateIndex",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) DeleteIndex(uid string) (*TaskInfo, error) {
|
|
return m.DeleteIndexWithContext(context.Background(), uid)
|
|
}
|
|
|
|
func (m *meilisearch) DeleteIndexWithContext(ctx context.Context, uid string) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/indexes/" + uid,
|
|
method: http.MethodDelete,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusAccepted},
|
|
functionName: "DeleteIndex",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) MultiSearch(queries *MultiSearchRequest) (*MultiSearchResponse, error) {
|
|
return m.MultiSearchWithContext(context.Background(), queries)
|
|
}
|
|
|
|
func (m *meilisearch) MultiSearchWithContext(ctx context.Context, queries *MultiSearchRequest) (*MultiSearchResponse, error) {
|
|
resp := new(MultiSearchResponse)
|
|
|
|
for i := 0; i < len(queries.Queries); i++ {
|
|
queries.Queries[i].validate()
|
|
}
|
|
|
|
req := &internalRequest{
|
|
endpoint: "/multi-search",
|
|
method: http.MethodPost,
|
|
contentType: contentTypeJSON,
|
|
withRequest: queries,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "MultiSearch",
|
|
}
|
|
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) CreateKey(request *Key) (*Key, error) {
|
|
return m.CreateKeyWithContext(context.Background(), request)
|
|
}
|
|
|
|
func (m *meilisearch) CreateKeyWithContext(ctx context.Context, request *Key) (*Key, error) {
|
|
parsedRequest := convertKeyToParsedKey(*request)
|
|
resp := new(Key)
|
|
req := &internalRequest{
|
|
endpoint: "/keys",
|
|
method: http.MethodPost,
|
|
contentType: contentTypeJSON,
|
|
withRequest: &parsedRequest,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusCreated},
|
|
functionName: "CreateKey",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) GetKey(identifier string) (*Key, error) {
|
|
return m.GetKeyWithContext(context.Background(), identifier)
|
|
}
|
|
|
|
func (m *meilisearch) GetKeyWithContext(ctx context.Context, identifier string) (*Key, error) {
|
|
resp := new(Key)
|
|
req := &internalRequest{
|
|
endpoint: "/keys/" + identifier,
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetKey",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) GetKeys(param *KeysQuery) (*KeysResults, error) {
|
|
return m.GetKeysWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) GetKeysWithContext(ctx context.Context, param *KeysQuery) (*KeysResults, error) {
|
|
resp := new(KeysResults)
|
|
req := &internalRequest{
|
|
endpoint: "/keys",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetKeys",
|
|
}
|
|
if param != nil && param.Limit != 0 {
|
|
req.withQueryParams["limit"] = strconv.FormatInt(param.Limit, 10)
|
|
}
|
|
if param != nil && param.Offset != 0 {
|
|
req.withQueryParams["offset"] = strconv.FormatInt(param.Offset, 10)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) UpdateKey(keyOrUID string, request *Key) (*Key, error) {
|
|
return m.UpdateKeyWithContext(context.Background(), keyOrUID, request)
|
|
}
|
|
|
|
func (m *meilisearch) UpdateKeyWithContext(ctx context.Context, keyOrUID string, request *Key) (*Key, error) {
|
|
parsedRequest := KeyUpdate{Name: request.Name, Description: request.Description}
|
|
resp := new(Key)
|
|
req := &internalRequest{
|
|
endpoint: "/keys/" + keyOrUID,
|
|
method: http.MethodPatch,
|
|
contentType: contentTypeJSON,
|
|
withRequest: &parsedRequest,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "UpdateKey",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) DeleteKey(keyOrUID string) (bool, error) {
|
|
return m.DeleteKeyWithContext(context.Background(), keyOrUID)
|
|
}
|
|
|
|
func (m *meilisearch) DeleteKeyWithContext(ctx context.Context, keyOrUID string) (bool, error) {
|
|
req := &internalRequest{
|
|
endpoint: "/keys/" + keyOrUID,
|
|
method: http.MethodDelete,
|
|
withRequest: nil,
|
|
withResponse: nil,
|
|
acceptedStatusCodes: []int{http.StatusNoContent},
|
|
functionName: "DeleteKey",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (m *meilisearch) GetTask(taskUID int64) (*Task, error) {
|
|
return m.GetTaskWithContext(context.Background(), taskUID)
|
|
}
|
|
|
|
func (m *meilisearch) GetTaskWithContext(ctx context.Context, taskUID int64) (*Task, error) {
|
|
return getTask(ctx, m.client, taskUID)
|
|
}
|
|
|
|
func (m *meilisearch) GetTasks(param *TasksQuery) (*TaskResult, error) {
|
|
return m.GetTasksWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) GetTasksWithContext(ctx context.Context, param *TasksQuery) (*TaskResult, error) {
|
|
resp := new(TaskResult)
|
|
req := &internalRequest{
|
|
endpoint: "/tasks",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetTasks",
|
|
}
|
|
if param != nil {
|
|
encodeTasksQuery(param, req)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) CancelTasks(param *CancelTasksQuery) (*TaskInfo, error) {
|
|
return m.CancelTasksWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) CancelTasksWithContext(ctx context.Context, param *CancelTasksQuery) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/tasks/cancel",
|
|
method: http.MethodPost,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "CancelTasks",
|
|
}
|
|
if param != nil {
|
|
paramToSend := &TasksQuery{
|
|
UIDS: param.UIDS,
|
|
IndexUIDS: param.IndexUIDS,
|
|
Statuses: param.Statuses,
|
|
Types: param.Types,
|
|
BeforeEnqueuedAt: param.BeforeEnqueuedAt,
|
|
AfterEnqueuedAt: param.AfterEnqueuedAt,
|
|
BeforeStartedAt: param.BeforeStartedAt,
|
|
AfterStartedAt: param.AfterStartedAt,
|
|
}
|
|
encodeTasksQuery(paramToSend, req)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) DeleteTasks(param *DeleteTasksQuery) (*TaskInfo, error) {
|
|
return m.DeleteTasksWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) DeleteTasksWithContext(ctx context.Context, param *DeleteTasksQuery) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/tasks",
|
|
method: http.MethodDelete,
|
|
withRequest: nil,
|
|
withResponse: &resp,
|
|
withQueryParams: map[string]string{},
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "DeleteTasks",
|
|
}
|
|
if param != nil {
|
|
paramToSend := &TasksQuery{
|
|
UIDS: param.UIDS,
|
|
IndexUIDS: param.IndexUIDS,
|
|
Statuses: param.Statuses,
|
|
Types: param.Types,
|
|
CanceledBy: param.CanceledBy,
|
|
BeforeEnqueuedAt: param.BeforeEnqueuedAt,
|
|
AfterEnqueuedAt: param.AfterEnqueuedAt,
|
|
BeforeStartedAt: param.BeforeStartedAt,
|
|
AfterStartedAt: param.AfterStartedAt,
|
|
BeforeFinishedAt: param.BeforeFinishedAt,
|
|
AfterFinishedAt: param.AfterFinishedAt,
|
|
}
|
|
encodeTasksQuery(paramToSend, req)
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) SwapIndexes(param []*SwapIndexesParams) (*TaskInfo, error) {
|
|
return m.SwapIndexesWithContext(context.Background(), param)
|
|
}
|
|
|
|
func (m *meilisearch) SwapIndexesWithContext(ctx context.Context, param []*SwapIndexesParams) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/swap-indexes",
|
|
method: http.MethodPost,
|
|
contentType: contentTypeJSON,
|
|
withRequest: param,
|
|
withResponse: &resp,
|
|
acceptedStatusCodes: []int{http.StatusAccepted},
|
|
functionName: "SwapIndexes",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) WaitForTask(taskUID int64, interval time.Duration) (*Task, error) {
|
|
return waitForTask(context.Background(), m.client, taskUID, interval)
|
|
}
|
|
|
|
func (m *meilisearch) WaitForTaskWithContext(ctx context.Context, taskUID int64, interval time.Duration) (*Task, error) {
|
|
return waitForTask(ctx, m.client, taskUID, interval)
|
|
}
|
|
|
|
func (m *meilisearch) GenerateTenantToken(
|
|
apiKeyUID string,
|
|
searchRules map[string]interface{},
|
|
options *TenantTokenOptions,
|
|
) (string, error) {
|
|
// validate the arguments
|
|
if searchRules == nil {
|
|
return "", fmt.Errorf("GenerateTenantToken: The search rules added in the token generation " +
|
|
"must be of type array or object")
|
|
}
|
|
if (options == nil || options.APIKey == "") && m.client.apiKey == "" {
|
|
return "", fmt.Errorf("GenerateTenantToken: The API key used for the token " +
|
|
"generation must exist and be a valid meilisearch key")
|
|
}
|
|
if apiKeyUID == "" || !IsValidUUID(apiKeyUID) {
|
|
return "", fmt.Errorf("GenerateTenantToken: The uid used for the token " +
|
|
"generation must exist and comply to uuid4 format")
|
|
}
|
|
if options != nil && !options.ExpiresAt.IsZero() && options.ExpiresAt.Before(time.Now()) {
|
|
return "", fmt.Errorf("GenerateTenantToken: When the expiresAt field in " +
|
|
"the token generation has a value, it must be a date set in the future")
|
|
}
|
|
|
|
var secret string
|
|
if options == nil || options.APIKey == "" {
|
|
secret = m.client.apiKey
|
|
} else {
|
|
secret = options.APIKey
|
|
}
|
|
|
|
// For HMAC signing method, the key should be any []byte
|
|
hmacSampleSecret := []byte(secret)
|
|
|
|
// Create the claims
|
|
claims := TenantTokenClaims{}
|
|
if options != nil && !options.ExpiresAt.IsZero() {
|
|
claims.RegisteredClaims = jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(options.ExpiresAt),
|
|
}
|
|
}
|
|
claims.APIKeyUID = apiKeyUID
|
|
claims.SearchRules = searchRules
|
|
|
|
// Create a new token object, specifying signing method and the claims
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
|
|
// Sign and get the complete encoded token as a string using the secret
|
|
tokenString, err := token.SignedString(hmacSampleSecret)
|
|
|
|
return tokenString, err
|
|
}
|
|
|
|
func (m *meilisearch) GetStats() (*Stats, error) {
|
|
return m.GetStatsWithContext(context.Background())
|
|
}
|
|
|
|
func (m *meilisearch) GetStatsWithContext(ctx context.Context) (*Stats, error) {
|
|
resp := new(Stats)
|
|
req := &internalRequest{
|
|
endpoint: "/stats",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetStats",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) CreateDump() (*TaskInfo, error) {
|
|
return m.CreateDumpWithContext(context.Background())
|
|
}
|
|
|
|
func (m *meilisearch) CreateDumpWithContext(ctx context.Context) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/dumps",
|
|
method: http.MethodPost,
|
|
contentType: contentTypeJSON,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusAccepted},
|
|
functionName: "CreateDump",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) Version() (*Version, error) {
|
|
return m.VersionWithContext(context.Background())
|
|
}
|
|
|
|
func (m *meilisearch) VersionWithContext(ctx context.Context) (*Version, error) {
|
|
resp := new(Version)
|
|
req := &internalRequest{
|
|
endpoint: "/version",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "Version",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) Health() (*Health, error) {
|
|
return m.HealthWithContext(context.Background())
|
|
}
|
|
|
|
func (m *meilisearch) HealthWithContext(ctx context.Context) (*Health, error) {
|
|
resp := new(Health)
|
|
req := &internalRequest{
|
|
endpoint: "/health",
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "Health",
|
|
}
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) CreateSnapshot() (*TaskInfo, error) {
|
|
return m.CreateSnapshotWithContext(context.Background())
|
|
}
|
|
|
|
func (m *meilisearch) CreateSnapshotWithContext(ctx context.Context) (*TaskInfo, error) {
|
|
resp := new(TaskInfo)
|
|
req := &internalRequest{
|
|
endpoint: "/snapshots",
|
|
method: http.MethodPost,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusAccepted},
|
|
contentType: contentTypeJSON,
|
|
functionName: "CreateSnapshot",
|
|
}
|
|
|
|
if err := m.client.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (m *meilisearch) IsHealthy() bool {
|
|
res, err := m.HealthWithContext(context.Background())
|
|
return err == nil && res.Status == "available"
|
|
}
|
|
|
|
func (m *meilisearch) Close() {
|
|
m.client.client.CloseIdleConnections()
|
|
}
|
|
|
|
func getTask(ctx context.Context, cli *client, taskUID int64) (*Task, error) {
|
|
resp := new(Task)
|
|
req := &internalRequest{
|
|
endpoint: "/tasks/" + strconv.FormatInt(taskUID, 10),
|
|
method: http.MethodGet,
|
|
withRequest: nil,
|
|
withResponse: resp,
|
|
acceptedStatusCodes: []int{http.StatusOK},
|
|
functionName: "GetTask",
|
|
}
|
|
if err := cli.executeRequest(ctx, req); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func waitForTask(ctx context.Context, cli *client, taskUID int64, interval time.Duration) (*Task, error) {
|
|
if interval == 0 {
|
|
interval = 50 * time.Millisecond
|
|
}
|
|
|
|
// extract closure to get the task and check the status first before the ticker
|
|
fn := func() (*Task, error) {
|
|
getTask, err := getTask(ctx, cli, taskUID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if getTask.Status != TaskStatusEnqueued && getTask.Status != TaskStatusProcessing {
|
|
return getTask, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// run first before the ticker, we do not want to wait for the first interval
|
|
task, err := fn()
|
|
if err != nil {
|
|
// Return error if it exists
|
|
return nil, err
|
|
}
|
|
|
|
// Return task if it exists
|
|
if task != nil {
|
|
return task, nil
|
|
}
|
|
|
|
// Create a ticker to check the task status, because our initial check was not successful
|
|
ticker := time.NewTicker(interval)
|
|
|
|
// Defer the stop of the ticker, help GC to cleanup
|
|
defer func() {
|
|
// we might want to revist this, go.mod now is 1.16
|
|
// however I still encouter the issue on go 1.22.2
|
|
// there are 2 issues regarding tickers
|
|
// https://go-review.googlesource.com/c/go/+/512355
|
|
// https://github.com/golang/go/issues/61542
|
|
ticker.Stop()
|
|
ticker = nil
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
case <-ticker.C:
|
|
task, err := fn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if task != nil {
|
|
return task, nil
|
|
}
|
|
}
|
|
}
|
|
}
|