From 4f9f0a25d2f6b93c682e9ad76adf60be70e5ef7c Mon Sep 17 00:00:00 2001 From: VictoriqueMoe Date: Tue, 12 Mar 2024 20:26:56 +0000 Subject: [PATCH] WIP --- .gitattributes | 2 + .gitignore | 136 +++++++++++++++++++++ go.mod | 3 + pkg/main.go | 204 ++++++++++++++++++++++++++++++++ pkg/mod/get_file_opts.go | 11 ++ pkg/mod/waifu_error.go | 7 ++ pkg/mod/waifu_response.go | 15 +++ pkg/mod/waifu_vault.go | 9 ++ pkg/mod/waifu_vault_put_opts.go | 29 +++++ 9 files changed, 416 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 pkg/main.go create mode 100644 pkg/mod/get_file_opts.go create mode 100644 pkg/mod/waifu_error.go create mode 100644 pkg/mod/waifu_response.go create mode 100644 pkg/mod/waifu_vault.go create mode 100644 pkg/mod/waifu_vault_put_opts.go diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5a0d5e4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7aaf72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,136 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* +**/*.iml +.idea/ +.idea/** +/build +**build/** +**.idea/** diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..be776b4 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module waifuVault-go-api + +go 1.21.0 diff --git a/pkg/main.go b/pkg/main.go new file mode 100644 index 0000000..e864f76 --- /dev/null +++ b/pkg/main.go @@ -0,0 +1,204 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "path/filepath" + "waifuVault-go-api/pkg/mod" +) + +const baseUrl = "https://waifuvault.moe" + +var client = &http.Client{} +var WaifuVault = waifuvalt{} + +func main() { + /*url := "http://localhost:3001/" + // don't worry about errors + response, _ := http.Get(url) + var target = mod.WaifuResponse[string]{} + err := json.NewDecoder(response.Body).Decode(&target) + if err != nil { + return + } + fmt.Print(target)*/ + /*fileDir, _ := os.Getwd() + fileName := "main.go" + filePath := path.Join(fileDir, "pkg", fileName) + b, err := os.ReadFile(filePath) + if err != nil { + fmt.Print(err) + return + } + fileNames := "main.go"*/ + + opts := mod.WaifuvaultPutOpts{ + Url: "https://victorique.moe/img/slider/Quotes.jpg", + HideFilename: true, + Expires: "1h", + } + file, err := WaifuVault.UploadFile(opts) + if err != nil { + fmt.Print(err) + return + } + fmt.Print(file) +} + +type waifuvalt struct { +} + +func (re *waifuvalt) UploadFile(options mod.WaifuvaultPutOpts) (*mod.WaifuResponse[string], error) { + if options.File != nil && options.Bytes != nil && options.Url != "" || options.File == nil && options.Bytes == nil && options.Url == "" { + return nil, errors.New("you can only supply buffer, file or url") + } + + body := bytes.Buffer{} + var writer *multipart.Writer + if options.File != nil || options.Bytes != nil { + + var fileBytes *bytes.Buffer + var w io.Writer + var err error + writer = multipart.NewWriter(&body) + if options.File != nil { + fileBytes = bytes.NewBuffer(nil) + _, err = io.Copy(fileBytes, options.File) + if err != nil { + return nil, err + } + w, err = writer.CreateFormFile("file", filepath.Base(options.File.Name())) + } else { + fileBytes = bytes.NewBuffer(*options.Bytes) + if options.FileName == "" { + return nil, errors.New("FileName must be set if bytes is used") + } + w, err = writer.CreateFormFile("file", options.FileName) + } + + if err != nil { + return nil, err + } + + if _, err = w.Write(fileBytes.Bytes()); err != nil { + return nil, err + } + err = writer.Close() + if err != nil { + return nil, err + } + } else if options.Url != "" { + bodyUrl := fmt.Sprintf(`{"url": "%s"}`, options.Url) + body = *bytes.NewBuffer([]byte(bodyUrl)) + } + + uploadUrl := getUrl(map[string]any{ + "expires": options.Expires, + "hide_filename": options.HideFilename, + "password": options.Password, + }, nil) + + r, err := createRequest(http.MethodPut, uploadUrl, &body, writer) + if err != nil { + return nil, err + } + resp, err := client.Do(r) + if err != nil { + return nil, err + } + return getResponse[string](resp) +} + +func createRequest(method, url string, body io.Reader, writer *multipart.Writer) (*http.Request, error) { + r, err := http.NewRequest(method, url, body) + if err != nil { + return nil, err + } + if writer != nil { + r.Header.Add("Content-Type", writer.FormDataContentType()) + } else { + r.Header.Set("Content-Type", "application/json") + } + return r, nil +} + +func (re *waifuvalt) FileInfo(token string) (*mod.WaifuResponse[string], error) { + return nil, nil +} + +func (re *waifuvalt) FileInfoFormatted(token string) (*mod.WaifuResponse[int], error) { + return nil, nil +} + +func (re *waifuvalt) DeleteFile(token string) (bool, error) { + return false, nil +} + +func (re *waifuvalt) GetFile(options mod.GetFileInfo) ([]byte, error) { + return nil, nil +} + +func getUrl(obj map[string]any, path *string) string { + baseRestUrl := fmt.Sprintf("%s/rest", baseUrl) + if path != nil { + baseRestUrl += "/" + *path + } + if obj == nil { + return baseRestUrl + } + + params := url.Values{} + for key, val := range obj { + if val == nil || val == "" { + continue + } + params.Add(key, fmt.Sprintf("%v", val)) + } + + if len(params) > 0 { + return fmt.Sprintf("%s?%s", baseRestUrl, params.Encode()) + } + + return baseRestUrl +} + +func getResponse[T string | int](response *http.Response) (*mod.WaifuResponse[T], error) { + err := checkError(response) + if err != nil { + return nil, err + } + bodyBytes, _ := io.ReadAll(response.Body) + var target = &mod.WaifuResponse[T]{} + err = json.Unmarshal(bodyBytes, target) + if err != nil { + return nil, err + } + return target, nil +} + +func checkError(response *http.Response) error { + if response.StatusCode < 200 || response.StatusCode > 299 { + bodyBytes, _ := io.ReadAll(response.Body) + errStr := string(bodyBytes) + + var respErrorJson mod.WaifuError + jsonErr := json.Unmarshal(bodyBytes, &respErrorJson) + + if jsonErr != nil { + errStr = fmt.Sprintf("Error %d (%s): %s", respErrorJson.Status, respErrorJson.Name, respErrorJson.Message) + } + + return errors.New(errStr) + } + return nil +} + +func ToPtr[T any](x T) *T { + return &x +} diff --git a/pkg/mod/get_file_opts.go b/pkg/mod/get_file_opts.go new file mode 100644 index 0000000..2d9e239 --- /dev/null +++ b/pkg/mod/get_file_opts.go @@ -0,0 +1,11 @@ +package mod + +type GetFileInfo struct { + // Password for this file + Password string + // the file token + Token string + // the filename and the file upload epoch. for example, 1710111505084/08.png. + // files with hidden filenames will only contain the epoch with ext. for example, 1710111505084.png + Filename string +} diff --git a/pkg/mod/waifu_error.go b/pkg/mod/waifu_error.go new file mode 100644 index 0000000..63b9726 --- /dev/null +++ b/pkg/mod/waifu_error.go @@ -0,0 +1,7 @@ +package mod + +type WaifuError struct { + Name string // The name of the HTTP status. e.g: Bad Request + Message string // the message or reason why the request failed + Status int // the http status returned +} diff --git a/pkg/mod/waifu_response.go b/pkg/mod/waifu_response.go new file mode 100644 index 0000000..eb98d59 --- /dev/null +++ b/pkg/mod/waifu_response.go @@ -0,0 +1,15 @@ +package mod + +// WaifuResponse is the response from the api for files and uploads +type WaifuResponse[T string | int] struct { + // Token for the uploaded file + Token string `json:"token"` + // URL to the uploaded file + URL string `json:"url"` + // Protected is if this file is protected-protected/encrypted + Protected bool `json:"protected"` + // RetentionPeriod is a string or a number that represents + // when the file will expire, if called with `format` true, then + // this will be a string like "332 days 7 hours 18 minutes 8 seconds" + RetentionPeriod T `json:"retentionPeriod"` +} diff --git a/pkg/mod/waifu_vault.go b/pkg/mod/waifu_vault.go new file mode 100644 index 0000000..ad6121b --- /dev/null +++ b/pkg/mod/waifu_vault.go @@ -0,0 +1,9 @@ +package mod + +type Waifuvalt interface { + UploadFile(options WaifuvaultPutOpts) (*WaifuResponse[string], error) + FileInfo(token string) (*WaifuResponse[string], error) + FileInfoFormatted(token string) (*WaifuResponse[int], error) + DeleteFile(token string) (bool, error) + GetFile(options GetFileInfo) ([]byte, error) +} diff --git a/pkg/mod/waifu_vault_put_opts.go b/pkg/mod/waifu_vault_put_opts.go new file mode 100644 index 0000000..6cf2e97 --- /dev/null +++ b/pkg/mod/waifu_vault_put_opts.go @@ -0,0 +1,29 @@ +package mod + +import "os" + +type WaifuvaultPutOpts struct { + + // A string containing a number and a letter of `m` for mins, `h` for hours, `d` for days. + // For example, `1h` would be 1 hour and `1d` would be 1 day. + // Omit this if you want the file to exist, according to the retention policy + Expires string + + // if set to true, then your filename will not appear in the URL. if false, then it will appear in the URL. defaults to false + HideFilename bool + + // Setting a password will encrypt the file + Password string + + //The file object on disk + File *os.File + + // the raw bytes of the file + Bytes *[]byte + + //An url to the file you want uploaded + Url string + + // The filename if `Bytes` is used + FileName string +}