package agecemorg import ( "bytes" "encoding/json" "fmt" "io" "mime/multipart" "net/http" "net/url" "codeberg.org/vlbeaudoin/voki/v3" "github.com/spf13/viper" ) type API struct { Voki *voki.Voki } // NewAPIClientFromViper returns a pointer to a new API object, // provided the configuration options are managed by // https://git.agecem.com/agecem/agecem-org/config func NewAPIClientFromViper(client *http.Client) (api *API, err error) { var config Config if err = viper.Unmarshal(&config); err != nil { return nil, err } return NewAPIClient(client, config.Server.Api.Host, config.Server.Api.Key, config.Server.Api.Port, config.Server.Api.Protocol) } func NewAPIClient(client *http.Client, host, key string, port int, protocol string) (*API, error) { return &API{Voki: voki.New(client, host, key, port, protocol)}, nil } func (a *API) UploadDocuments(bucketName string, fileHeaders ...*multipart.FileHeader) (response CreateDocumentsResponse, err error) { if count := len(fileHeaders); count == 0 { err = fmt.Errorf("api.(*API).UploadDocuments requiert au moins 1 fichier") return } endpoint := fmt.Sprintf("%s://%s:%d/v1/bucket/%s/many", a.Voki.Protocol, a.Voki.Host, a.Voki.Port, bucketName, ) // Create new multipart writer body := &bytes.Buffer{} writer := multipart.NewWriter(body) // Add files to the request for i, fileHeader := range fileHeaders { if fileHeader == nil { return response, fmt.Errorf("Fichier %d pointe vers une addresse mémoire nulle", i) } file, err := fileHeader.Open() if err != nil { return response, fmt.Errorf("Impossible de lire le contenu du fichier %d '%s': %s", i, fileHeader.Filename, err) } defer file.Close() fileName, err := url.QueryUnescape(fileHeader.Filename) if err != nil { return response, fmt.Errorf("Fichier %d '%s' a un nom invalide et impossible à convertir: %s", i, fileHeader.Filename, err) } part, err := writer.CreatePart(fileHeader.Header) if err != nil { return response, fmt.Errorf("Impossible d'ajouter %d '%s' au formulaire de téléversement: %s", i, fileName, err) } _, err = io.Copy(part, file) if err != nil { return response, fmt.Errorf("Impossible d'ajouter le contenu de %d '%s' au formulaire de téléversement: %s", i, fileName, err) } } if err := writer.Close(); err != nil { return response, fmt.Errorf("Impossible de fermer le io.Writer: %s", err) } req, err := http.NewRequest(http.MethodPost, endpoint, body) if err != nil { return response, fmt.Errorf("Impossible de produire une requête: %s", err) } if err := req.ParseForm(); err != nil { return response, fmt.Errorf("Impossible de parse le formulaire: %s", err) } req.Header.Set("Content-Type", writer.FormDataContentType()) if a.Voki.Key != "" { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.Voki.Key)) } // Send the HTTP request httpResponse, err := a.Voki.Client.Do(req) if err != nil { return response, fmt.Errorf("Impossible d'exécuter la requête http: %s", err) } defer httpResponse.Body.Close() return response, json.NewDecoder(httpResponse.Body).Decode(&response) } func (a *API) UploadDocument(bucket string, file_header *multipart.FileHeader) (response CreateDocumentResponse, err error) { endpoint := fmt.Sprintf("%s://%s:%d", a.Voki.Protocol, a.Voki.Host, a.Voki.Port, ) current_url := fmt.Sprintf("%s/v1/bucket/%s", endpoint, bucket) // Create a new multipart writer body := &bytes.Buffer{} writer := multipart.NewWriter(body) // Add the file to the request file, err := file_header.Open() if err != nil { return response, fmt.Errorf("UploadDocument#file_header.Open: %s", err) } defer file.Close() filename_processed, err := url.QueryUnescape(file_header.Filename) if err != nil { return response, fmt.Errorf("UploadDocument#url.QueryUnescape: %s", err) } part, err := writer.CreateFormFile("document", filename_processed) if err != nil { return response, fmt.Errorf("UploadDocument#writer.CreateFormFile: %s", err) } _, err = io.Copy(part, file) if err != nil { return response, fmt.Errorf("UploadDocument#io.Copy: %s", err) } err = writer.Close() if err != nil { return response, fmt.Errorf("UploadDocument#writer.Close: %s", err) } // Create a new HTTP request with the multipart body req, err := http.NewRequest(http.MethodPost, current_url, body) if err != nil { return response, fmt.Errorf("UploadDocument#http.NewRequest: %s", err) } req.Header.Set("Content-Type", writer.FormDataContentType()) if a.Voki.Key != "" { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", a.Voki.Key)) } // Send the HTTP request client := &http.Client{} resp, err := client.Do(req) if err != nil { return response, fmt.Errorf("UploadDocument#client.Do: %s", err) } defer resp.Body.Close() err = json.NewDecoder(resp.Body).Decode(&response) return response, err } func (a *API) ListBuckets() (response ListBucketsResponse, err error) { return response, a.Voki.Unmarshal(http.MethodGet, "/v1/bucket", nil, true, &response) } func (a *API) ReadBucket(bucket string) (response ReadBucketResponse, err error) { return response, a.Voki.Unmarshal(http.MethodGet, fmt.Sprintf("/v1/bucket/%s", bucket), nil, true, &response) } func (a *API) UpdateDocumentKey(bucket, document, newKey string) (response UpdateDocumentKeyResponse, err error) { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(newKey); err != nil { return response, fmt.Errorf("handler: %s", err) } return response, a.Voki.Unmarshal(http.MethodPut, fmt.Sprintf("/v1/bucket/%s/%s/key", bucket, document), &buf, true, &response) } func (a *API) DeleteDocument(bucket, document string) (response DeleteDocumentResponse, err error) { return response, a.Voki.Unmarshal(http.MethodDelete, fmt.Sprintf("/v1/bucket/%s/%s", bucket, document), nil, true, &response) } func (a *API) Seed() (response ExecuteSeedResponse, err error) { request, err := NewV1SeedPOST() if err != nil { return } return request.Request(a.Voki) }