BedrockFetch/tea/tea.go
Matheus Sampaio Queiroga 27021fde73
All checks were successful
Find and Upload Minecraft Server versions / build (push) Successful in 14s
Fix upload
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2024-08-22 15:25:47 -03:00

227 lines
6.5 KiB
Go

package tea
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"strings"
"time"
"sirherobrine23.org/go-bds/go-bds/request"
)
const Repo string = "go-bds/BedrockFetch" // Default repository
var (
Token string = (func() string {
if ghToken := os.Getenv("GH_TOKEN"); len(ghToken) > 0 {
return ghToken
} else if githubToken := os.Getenv("GITHUB_TOKEN"); len(githubToken) > 0 {
return githubToken
} else if giteaToken := os.Getenv("GITEA_TOKEN"); len(giteaToken) > 0 {
return giteaToken
}
return ""
})()
RootURL string = func() string {
if data := os.Getenv("GITHUB_SERVER_URL"); data != "" {
return data
}
return "https://sirherobrine23.com.br"
}()
GiteaReleaseURI = fmt.Sprintf("%s/api/v1/repos/%s/releases", RootURL, Repo) // Gitea api release
ErrToken error = errors.New("set Gitea token in Env (GH_TOKEN || GITHUB_TOKEN || GITEA_TOKEN)")
ErrBackend error = errors.New("catch 500 error in server api")
ErrNoExist error = errors.New("repository, organization or endpoint dont exists")
)
type GiteaAsset struct {
Id int64 `json:"id"`
FileSize int64 `json:"size"`
Downloads int64 `json:"download_count"`
Uuid string `json:"uuid"`
FileUrl string `json:"browser_download_url"`
FileName string `json:"name"`
Create time.Time `json:"created_at"`
}
type GiteaRelease struct {
ReleaseId int64 `json:"id,omitempty"` // Release id
TagName string `json:"tag_name"` // Release tag name
Name string `json:"name,omitempty"` // Release name
Body string `json:"body,omitempty"` // Release body
IsPrerelease bool `json:"prerelease"` // Set Pre-release
IsDraft bool `json:"draft"` // Set release to draft
FileAssets []GiteaAsset `json:"assets,omitempty"` // Files in release
}
type giteaError struct {
Errors []string `json:"errors"`
TeaError string `json:"error"`
Message string `json:"message"`
Url string `json:"url"`
}
func processGiteaError(res *http.Response) error {
switch res.StatusCode {
case 401:
return ErrToken
case 409:
return fmt.Errorf("error format response")
case 422:
return fmt.Errorf("error in format response related to input validation")
case 404:
if strings.Contains(res.Header.Get("Content-Type"), "application/json") {
var data giteaError
defer res.Body.Close()
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
return ErrNoExist
} else if len(data.Errors) > 0 {
return fmt.Errorf("gitea api, errors: %s, %s", data.Message, strings.Join(data.Errors, ", "))
}
return fmt.Errorf(data.Message)
}
return ErrNoExist
case 500, 501:
if strings.Contains(res.Header.Get("Content-Type"), "application/json") {
var data giteaError
defer res.Body.Close()
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
return ErrNoExist
} else if len(data.Errors) > 0 {
return fmt.Errorf("gitea api, errors: %s, %s", data.Message, strings.Join(data.Errors, ", "))
}
return fmt.Errorf(data.Message)
}
return ErrBackend
}
return nil
}
func processJsonRequest(req request.RequestOptions, targetStruct any) (*http.Response, error) {
res, err := req.Request()
if err != nil {
if res == nil {
return res, err
}
originalErr := err
if err = processGiteaError(res); err != nil {
return res, err
}
return res, originalErr
}
defer res.Body.Close()
if err = processGiteaError(res); err != nil {
return res, err
} else if err := json.NewDecoder(res.Body).Decode(targetStruct); err != nil {
return res, err
}
return res, nil
}
// Get release, if not exists create
func Release(IsPrerelease, Draft bool, TagName, Name, Body string) (*GiteaRelease, error) {
if TagName = strings.TrimSpace(TagName); len(TagName) == 0 {
return nil, fmt.Errorf("set valid tag to create release")
} else if Name = strings.TrimSpace(Name); len(Name) == 0 {
Name = TagName
}
var req request.RequestOptions
req.Url = fmt.Sprintf("%s/tags/%s", GiteaReleaseURI, TagName)
req.Headers = http.Header{}
if Token != "" {
req.Headers.Set("Authorization", fmt.Sprintf("token %s", Token))
}
var giteaRel GiteaRelease
res, err := processJsonRequest(req, &giteaRel)
if err != nil {
if res.StatusCode == 404 {
if len(Token) == 0 {
return nil, ErrToken
}
body, err := json.Marshal(&GiteaRelease{TagName: TagName, Name: Name, Body: Body, IsPrerelease: IsPrerelease, IsDraft: Draft})
if err != nil {
return nil, err
}
req.Method = "POST"
req.Url = GiteaReleaseURI
req.Body = bytes.NewReader(body)
req.Headers.Set("Content-Type", "application/json")
_, err = processJsonRequest(req, &giteaRel)
if err != nil {
return nil, fmt.Errorf("gitea api, create release: %s", err.Error())
}
return &giteaRel, nil
}
return nil, fmt.Errorf("gitea api: %s", err.Error())
}
return &giteaRel, nil
}
func (rel GiteaRelease) ExistsFile(filename string) bool {
return rel.GetFile(filename) != nil
}
func (rel GiteaRelease) GetFile(filename string) *GiteaAsset {
for _, asset := range rel.FileAssets {
if asset.FileName == filename {
return &asset
}
}
return nil
}
func (asset GiteaAsset) Download() (io.ReadCloser, error) {
var req request.RequestOptions
req.Headers = http.Header{"Authorization": {fmt.Sprintf("token %s", Token)}}
res, err := req.Request()
if err != nil {
return nil, err
} else if res.StatusCode != 200 {
return nil, fmt.Errorf("cannot get file")
}
return res.Body, err
}
type UploadMap map[string]io.Reader
func (rel *GiteaRelease) Upload(filename string, fileBody io.Reader) (*GiteaAsset, error) {
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("attachment", filename)
if err != nil {
return nil, err
} else if _, err = io.Copy(part, fileBody); err != nil {
return nil, err
} else if err = writer.Close(); err != nil {
return nil, err
}
var req request.RequestOptions
req.Url = fmt.Sprintf("%s/%d/assets", GiteaReleaseURI, rel.ReleaseId)
req.Method = "POST"
req.Headers = http.Header{"Authorization": {fmt.Sprintf("token %s", Token)}, "Content-Type": {writer.FormDataContentType()}}
req.Body = body
var asset GiteaAsset
res, err := req.Do(&asset)
if err != nil {
return nil, err
} else if res.StatusCode != 201 {
return nil, fmt.Errorf("cannot upload %q to release, code: %d (%s)", filename, res.StatusCode, res.Status)
}
rel.FileAssets = append(rel.FileAssets, asset)
return &asset, nil
}