Capture error strings for i18n

This commit is contained in:
iacore
2024-10-05 15:19:22 +00:00
parent 546f83df20
commit 2f4e95d002
19 changed files with 108 additions and 70 deletions
+5 -6
View File
@@ -3,8 +3,6 @@ package config
import (
"context"
"errors"
"fmt"
"log"
"net/url"
"strings"
@@ -15,6 +13,7 @@ import (
// "github.com/goware/urlx"
"github.com/sethvargo/go-envconfig"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/token_manager"
)
@@ -102,10 +101,10 @@ func validateURL(urlString string, urlType string) (*url.URL, error) {
}
// Ensure both scheme and host are present in the URL
if parsedURL.Scheme == "" || parsedURL.Host == "" {
return nil, fmt.Errorf("%s URL is invalid: %s. Please specify a complete URL with scheme and host, e.g. https://example.com", urlType, urlString)
return nil, i18n.Errorf("%s URL is invalid: %s. Please specify a complete URL with scheme and host, e.g. https://example.com", urlType, urlString)
}
if strings.HasSuffix(parsedURL.Path, "/") {
return nil, fmt.Errorf("%s URL path (%s) cannot end in /: %s. PixivFE does not support this now", urlType, parsedURL.Path, urlString)
return nil, i18n.Errorf("%s URL path (%s) cannot end in /: %s. PixivFE does not support this now", urlType, parsedURL.Path, urlString)
}
return parsedURL, nil
}
@@ -152,13 +151,13 @@ func (s *ServerConfig) LoadConfig() error {
if s.Port == "" && s.UnixSocket == "" {
log.Fatalln("Either PIXIVFE_PORT or PIXIVFE_UNIXSOCKET has to be set.")
return errors.New("Either PIXIVFE_PORT or PIXIVFE_UNIXSOCKET has to be set")
return i18n.Error("Either PIXIVFE_PORT or PIXIVFE_UNIXSOCKET has to be set")
}
// a check for tokens
if len(s.Token) < 1 {
log.Fatalln("PIXIVFE_TOKEN has to be set. Visit https://pixivfe-docs.pages.dev/hosting/hosting-pixivfe for more details.")
return errors.New("PIXIVFE_TOKEN has to be set. Visit https://pixivfe-docs.pages.dev/hosting/hosting-pixivfe for more details")
return i18n.Error("PIXIVFE_TOKEN has to be set. Visit https://pixivfe-docs.pages.dev/hosting/hosting-pixivfe for more details")
}
// Validate proxy server URL
+6 -5
View File
@@ -1,12 +1,13 @@
package core
import (
"fmt"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"github.com/goccy/go-json"
"github.com/tidwall/gjson"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
)
func GetDiscoveryArtwork(r *http.Request, mode string) ([]ArtworkBrief, error) {
@@ -22,7 +23,7 @@ func GetDiscoveryArtwork(r *http.Request, mode string) ([]ArtworkBrief, error) {
}
resp = session.ProxyImageUrl(r, resp)
if !gjson.Valid(resp) {
return nil, fmt.Errorf("Invalid JSON: %v", resp)
return nil, i18n.Errorf("Invalid JSON: %v", resp)
}
data := gjson.Get(resp, "thumbnails.illust").String()
@@ -47,7 +48,7 @@ func GetDiscoveryNovels(r *http.Request, mode string) ([]NovelBrief, error) {
}
resp = session.ProxyImageUrl(r, resp)
if !gjson.Valid(resp) {
return nil, fmt.Errorf("Invalid JSON: %v", resp)
return nil, i18n.Errorf("Invalid JSON: %v", resp)
}
data := gjson.Get(resp, "thumbnails.novel").String()
+5 -3
View File
@@ -2,11 +2,13 @@ package core
import (
"fmt"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"github.com/goccy/go-json"
"github.com/tidwall/gjson"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
)
type Pixivision struct {
@@ -59,7 +61,7 @@ func GetLanding(r *http.Request, mode string) (*LandingArtworks, error) {
resp = session.ProxyImageUrl(r, resp)
if !gjson.Valid(resp) {
return nil, fmt.Errorf("Invalid JSON: %v", resp)
return nil, i18n.Errorf("Invalid JSON: %v", resp)
}
artworks := map[string]ArtworkBrief{}
+4 -3
View File
@@ -1,7 +1,6 @@
package core
import (
"errors"
"fmt"
"html"
"io"
@@ -10,6 +9,8 @@ import (
"time"
"github.com/PuerkitoBio/goquery"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
const PixivDatetimeLayout = "2006-01-02"
@@ -37,7 +38,7 @@ func executeRequest(req *http.Request) (*http.Response, error) {
client := http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if resp.StatusCode != 200 {
return nil, errors.New("Pixivision: Page not found")
return nil, i18n.Error("Pixivision: Page not found")
}
if err != nil {
return nil, err
@@ -126,7 +127,7 @@ func PixivisionGetHomepage(r *http.Request, page string, lang ...string) ([]Pixi
}
if resp.StatusCode == 404 {
return articles, errors.New("We couldn't find the page you're looking for")
return articles, i18n.Error("We couldn't find the page you're looking for")
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
+10 -10
View File
@@ -4,12 +4,12 @@ import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"time"
config "codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/audit"
"codeberg.org/vnpower/pixivfe/v2/server/request_context"
"codeberg.org/vnpower/pixivfe/v2/server/token_manager"
@@ -65,7 +65,7 @@ func retryRequest(ctx context.Context, reqFunc func(context.Context, string) (*r
if token == nil && !isPost {
tokenManager.ResetAllTokens()
return nil, fmt.Errorf("All tokens (%d) are timed out, resetting all tokens to their initial good state.\n"+
return nil, i18n.Errorf("All tokens (%d) are timed out, resetting all tokens to their initial good state.\n"+
"Consider providing additional tokens in PIXIVFE_TOKEN or reviewing API request level backoff configuration.\n"+
"Please refer the following documentation for additional information:\n"+
"- https://pixivfe-docs.pages.dev/hosting/obtaining-pixivfe-token/\n"+
@@ -118,7 +118,7 @@ func retryRequest(ctx context.Context, reqFunc func(context.Context, string) (*r
}, nil
}
lastErr = fmt.Errorf("HTTP status code: %d", resp.StatusCode)
lastErr = i18n.Errorf("HTTP status code: %d", resp.StatusCode)
if userToken == "" && !isPost {
tokenManager.MarkTokenStatus(token, token_manager.TimedOut)
@@ -132,7 +132,7 @@ func retryRequest(ctx context.Context, reqFunc func(context.Context, string) (*r
}
}
return nil, fmt.Errorf("Max retries reached. Last error: %v", lastErr)
return nil, i18n.Errorf("Max retries reached. Last error: %v", lastErr)
}
// API_GET performs a GET request to the Pixiv API with automatic retries
@@ -161,13 +161,13 @@ func API_GET_UnwrapJson(ctx context.Context, url string, userToken string) (stri
}
if !gjson.Valid(resp.Body) {
return "", fmt.Errorf("Invalid JSON: %v", resp.Body)
return "", i18n.Errorf("Invalid JSON: %v", resp.Body)
}
err2 := gjson.Get(resp.Body, "error")
if !err2.Exists() {
return "", errors.New("Incompatible request body")
return "", i18n.Error("Incompatible request body")
}
if err2.Bool() {
@@ -180,7 +180,7 @@ func API_GET_UnwrapJson(ctx context.Context, url string, userToken string) (stri
// API_POST performs a POST request to the Pixiv API with automatic retries
func API_POST(ctx context.Context, url, payload, userToken, csrf string, isJSON bool) error {
if userToken == "" {
return errors.New("userToken is required for POST requests")
return i18n.Error("userToken is required for POST requests")
}
_, err := retryRequest(ctx, func(ctx context.Context, token string) (*retryablehttp.Request, error) {
@@ -236,7 +236,7 @@ func proxyWorker(jobs <-chan ProxyJob) {
func processProxyJob(job ProxyJob) error {
resp, err := utils.HttpClient.Do(job.Request)
if err != nil {
return fmt.Errorf("failed to process request: %w", err)
return i18n.Errorf("failed to process request: %w", err)
}
defer resp.Body.Close()
@@ -252,7 +252,7 @@ func processProxyJob(job ProxyJob) error {
// Copy the body from the response to the original writer
_, err = io.Copy(job.Response, resp.Body)
if err != nil {
return fmt.Errorf("failed to copy response body: %w", err)
return i18n.Errorf("failed to copy response body: %w", err)
}
return nil
+5 -4
View File
@@ -1,14 +1,15 @@
package core
import (
"errors"
"fmt"
"math"
"sort"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"github.com/goccy/go-json"
"net/http"
)
// pixivfe internal data type. not used by pixiv.
@@ -30,7 +31,7 @@ func (s UserArtCategory) Validate() error {
s != UserArt_Manga &&
s != UserArt_Bookmarks &&
s != UserArt_Novel {
return fmt.Errorf("Invalid work category: %#v. "+`Only "%s", "%s", "%s", "%s", "%s" and "%s" are available`, s, UserArt_Any, UserArt_AnyAlt, UserArt_Illustration, UserArt_Manga, UserArt_Bookmarks, UserArt_Novel)
return i18n.Errorf("Invalid work category: %#v. "+`Only "%s", "%s", "%s", "%s", "%s" and "%s" are available`, s, UserArt_Any, UserArt_AnyAlt, UserArt_Illustration, UserArt_Manga, UserArt_Bookmarks, UserArt_Novel)
} else {
return nil
}
@@ -234,7 +235,7 @@ func GetUserArtworksID(r *http.Request, id string, category UserArtCategory, pag
worksPerPage := 30.0
if page < 1 || float64(page) > math.Ceil(worksNumber/worksPerPage)+1.0 {
return "", -1, errors.New("No page available.")
return "", -1, i18n.Error("No page available.")
}
start := (page - 1) * int(worksPerPage)
+16
View File
@@ -0,0 +1,16 @@
package i18n
import (
"errors"
"fmt"
)
func Error(text string) error {
text = Lookup(text)
return errors.New(text)
}
func Errorf(format string, a ...any) error {
format = Lookup(format)
return fmt.Errorf(format, a...)
}
+6
View File
@@ -0,0 +1,6 @@
package i18n
func Lookup(text string) string {
// todo
return text
}
+2 -2
View File
@@ -2,7 +2,6 @@ package main
import (
"context"
"fmt"
"log"
"net"
"net/http"
@@ -14,6 +13,7 @@ import (
"time"
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/audit"
"codeberg.org/vnpower/pixivfe/v2/server/middleware"
"codeberg.org/vnpower/pixivfe/v2/server/proxy_checker"
@@ -86,7 +86,7 @@ func run_sass() {
runtime.LockOSThread() // Go quirk https://github.com/golang/go/issues/27505
err := cmd.Run()
if err != nil {
log.Print(fmt.Errorf("when running sass: %w", err))
log.Print(i18n.Errorf("when running sass: %w", err), err)
}
}
+16 -8
View File
@@ -164,15 +164,23 @@ rules:
- pattern-not-inside: |
...
defer $RESP.Body.Close()
- id: "13"
message: "error string"
- id: "13a"
message: "untranslated errors.New"
languages: [go]
severity: INFO
pattern-either:
- pattern: |
errors.New(...)
- pattern: |
fmt.Errorf(...)
severity: ERROR
pattern: |
errors.New("$MSG")
fix: |
i18n.Error("$MSG")
- id: "13b"
message: "untranslated fmt.Errorf"
languages: [go]
severity: ERROR
pattern: |
fmt.Errorf("$MSG", $...ARGS)
fix: |
i18n.Errorf("$MSG", $...ARGS)
- id: "14"
message: "non-global regexp.MustCompile"
languages: [go]
+2 -2
View File
@@ -1,11 +1,11 @@
package audit
import (
"fmt"
"log"
"os"
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
var optionSaveResponse bool
@@ -26,7 +26,7 @@ func Init(saveResponse bool) error {
if err := os.MkdirAll(savePath, 0o700); err != nil {
log.Printf("Error creating response save directory: %v", err)
return fmt.Errorf("failed to create response save directory: %w", err)
return i18n.Errorf("failed to create response save directory: %w", err)
}
return nil
+4 -3
View File
@@ -3,14 +3,15 @@
package audit
import (
"fmt"
"log"
"os"
"path"
"time"
"codeberg.org/vnpower/pixivfe/v2/config"
"github.com/oklog/ulid/v2"
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
// Logger is a custom logger with no timestamp prefix, as we control the timestamps in our log messages.
@@ -77,7 +78,7 @@ func writeResponseBodyToFile(body string) (string, error) {
// Write the body to the file with read/write permissions for the owner only
err := os.WriteFile(filename, []byte(body), 0o600)
if err != nil {
return "", fmt.Errorf("failed to write response body to file %s: %w", filename, err)
return "", i18n.Errorf("failed to write response body to file %s: %w", filename, err)
}
log.Printf("Successfully wrote response body to file: %s", filename)
return filename, nil
+4 -3
View File
@@ -1,12 +1,13 @@
package middleware
import (
"errors"
"net/http"
"strings"
"codeberg.org/vnpower/pixivfe/v2/server/routes"
"github.com/gorilla/mux"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/routes"
)
// handleStripPrefix is a utility function that combines path prefix matching with
@@ -129,7 +130,7 @@ func DefineRoutes() *mux.Router {
// Fallback route (if nothing else matches)
// This ensures that a proper HTTP 404 error is returned for undefined routes
router.NewRoute().HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routes.ErrorPage(w, r, errors.New("Route not found"), http.StatusNotFound)
routes.ErrorPage(w, r, i18n.Error("Route not found"), http.StatusNotFound)
})
return router
+4 -4
View File
@@ -1,11 +1,11 @@
package routes
import (
"errors"
"fmt"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/core"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"codeberg.org/vnpower/pixivfe/v2/server/utils"
)
@@ -20,7 +20,7 @@ func AddBookmarkRoute(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if id == "" {
return errors.New("No ID provided.")
return i18n.Error("No ID provided.")
}
URL := "https://www.pixiv.net/ajax/illusts/bookmarks/add"
@@ -48,7 +48,7 @@ func DeleteBookmarkRoute(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if id == "" {
return errors.New("No ID provided.")
return i18n.Error("No ID provided.")
}
// You can't unlike
@@ -72,7 +72,7 @@ func LikeRoute(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if id == "" {
return errors.New("No ID provided.")
return i18n.Error("No ID provided.")
}
URL := "https://www.pixiv.net/ajax/illusts/like"
+3 -2
View File
@@ -2,16 +2,17 @@ package routes
import (
"fmt"
"net/http"
"strconv"
"codeberg.org/vnpower/pixivfe/v2/core"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
func ArtworkPage(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if _, err := strconv.Atoi(id); err != nil {
return fmt.Errorf("Invalid ID: %s", id)
return i18n.Errorf("Invalid ID: %s", id)
}
illust, err := core.GetArtworkByID(r, id, true)
+3 -2
View File
@@ -2,12 +2,13 @@ package routes
import (
"fmt"
"net/http"
"strconv"
"strings"
"sync"
"codeberg.org/vnpower/pixivfe/v2/core"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
func ArtworkMultiPage(w http.ResponseWriter, r *http.Request) error {
@@ -26,7 +27,7 @@ func ArtworkMultiPage(w http.ResponseWriter, r *http.Request) error {
var err_global error = nil
for i, id := range ids {
if _, err := strconv.Atoi(id); err != nil {
err_global = fmt.Errorf("Invalid ID: %s", id)
err_global = i18n.Errorf("Invalid ID: %s", id)
break
}
+3 -3
View File
@@ -2,19 +2,19 @@ package routes
import (
"fmt"
"net/http"
"strconv"
"strings"
"net/http"
"codeberg.org/vnpower/pixivfe/v2/core"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
)
func NovelPage(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if _, err := strconv.Atoi(id); err != nil {
return fmt.Errorf("Invalid ID: %s", id)
return i18n.Errorf("Invalid ID: %s", id)
}
novel, err := core.GetNovelByID(r, id)
+3 -2
View File
@@ -8,12 +8,13 @@ import (
"net/http"
"codeberg.org/vnpower/pixivfe/v2/core"
"codeberg.org/vnpower/pixivfe/v2/i18n"
)
func NovelSeriesPage(w http.ResponseWriter, r *http.Request) error {
id := GetPathVar(r, "id")
if _, err := strconv.Atoi(id); err != nil {
return fmt.Errorf("Invalid ID: %s", id)
return i18n.Errorf("Invalid ID: %s", id)
}
series, err := core.GetNovelSeriesByID(r, id)
@@ -28,7 +29,7 @@ func NovelSeriesPage(w http.ResponseWriter, r *http.Request) error {
page := GetQueryParam(r, "p", "1")
pageNum, err := strconv.Atoi(page)
if err != nil || pageNum < 1 || pageNum > pageLimit {
return fmt.Errorf("Invalid Page")
return i18n.Errorf("Invalid Page Number: %d", pageNum)
}
// TODO should use token only if R-18/R-18G
+7 -8
View File
@@ -1,8 +1,6 @@
package routes
import (
"errors"
"fmt"
"net/http"
"regexp"
"slices"
@@ -10,6 +8,7 @@ import (
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/core"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/proxy_checker"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"codeberg.org/vnpower/pixivfe/v2/server/utils"
@@ -24,7 +23,7 @@ func setToken(w http.ResponseWriter, r *http.Request) error {
_, err := core.API_GET_UnwrapJson(r.Context(), URL, token)
if err != nil {
return errors.New("Cannot authorize with supplied token.")
return i18n.Error("Cannot authorize with supplied token.")
}
// Make a test request to verify the token.
@@ -35,14 +34,14 @@ func setToken(w http.ResponseWriter, r *http.Request) error {
}
if resp.StatusCode != 200 {
return errors.New("Cannot authorize with supplied token.")
return i18n.Error("Cannot authorize with supplied token.")
}
// CSRF token
csrf := r_csrf.FindStringSubmatch(resp.Body)[1]
if csrf == "" {
return errors.New("Cannot authorize with supplied token.")
return i18n.Error("Cannot authorize with supplied token.")
}
// Set the token
@@ -51,7 +50,7 @@ func setToken(w http.ResponseWriter, r *http.Request) error {
return nil
}
return errors.New("You submitted an empty/invalid form.")
return i18n.Error("You submitted an empty/invalid form.")
}
func setImageServer(w http.ResponseWriter, r *http.Request) error {
@@ -127,7 +126,7 @@ func setCookie(w http.ResponseWriter, r *http.Request) error {
return nil
}
}
return fmt.Errorf("Invalid Cookie Name: %s", key)
return i18n.Errorf("Invalid Cookie Name: %s", key)
}
func setRawCookie(w http.ResponseWriter, r *http.Request) error {
@@ -189,7 +188,7 @@ func SettingsPost(w http.ResponseWriter, r *http.Request) error {
case "raw":
err = setRawCookie(w, r)
default:
err = errors.New("No such setting is available.")
err = i18n.Error("No such setting is available.")
}
if err != nil {