mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-08 14:15:00 +03:00
fix(i18n): publish the translation bundle only once it is complete
InitLocalizer filled the shared bundle in place, and the Telegram bot runs it again while the panel is serving, so a request could read the bundle's maps while they were being written and the process died on a concurrent map access. Build the bundle privately and publish it, and the bot and web localizers, through atomic pointers; the lazy load in the middleware publishes only if nothing else did first.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package locale
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type fixedLang string
|
||||
|
||||
func (l fixedLang) GetTgLang() (string, error) { return string(l), nil }
|
||||
|
||||
// The Telegram bot re-runs InitLocalizer while the panel serves requests; a request must
|
||||
// never read the bundle while it is being filled (a concurrent map access kills the process).
|
||||
func TestInitLocalizerWhileServingRequests(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
translations := fstest.MapFS{"translation/en_US.json": {Data: []byte(`{"hello": "Hello"}`)}}
|
||||
engine := gin.New()
|
||||
engine.Use(LocalizerMiddleware())
|
||||
engine.GET("/", func(c *gin.Context) { c.String(http.StatusOK, I18nForLang("en-US", "hello")) })
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Go(func() {
|
||||
for range 200 {
|
||||
if err := InitLocalizer(translations, fixedLang("en-US")); err != nil {
|
||||
t.Errorf("InitLocalizer: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
for range 4 {
|
||||
wg.Go(func() {
|
||||
for range 200 {
|
||||
engine.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil))
|
||||
}
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
rec := httptest.NewRecorder()
|
||||
engine.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||
if rec.Body.String() != "Hello" {
|
||||
t.Fatalf("after re-initialisation the bundle answers %q, want Hello", rec.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user