-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(init): Add support for geo ip pack initialization #7333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| package lang | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "path" | ||
| "sort" | ||
| "strings" | ||
|
|
||
| "github.com/1Panel-dev/1Panel/backend/global" | ||
| "github.com/1Panel-dev/1Panel/backend/utils/cmd" | ||
| "github.com/1Panel-dev/1Panel/backend/utils/files" | ||
| ) | ||
|
|
||
| func Init() { | ||
| go initLang() | ||
| } | ||
|
|
||
| func initLang() { | ||
| fileOp := files.NewFileOp() | ||
| geoPath := path.Join(global.CONF.System.BaseDir, "1panel/geo/GeoIP.mmdb") | ||
| isLangExist := fileOp.Stat("/usr/local/bin/lang/zh.sh") | ||
| isGeoExist := fileOp.Stat(geoPath) | ||
| if isLangExist && isGeoExist { | ||
| return | ||
| } | ||
| upgradePath := path.Join(global.CONF.System.BaseDir, "1panel/tmp/upgrade") | ||
| tmpPath, err := loadRestorePath(upgradePath) | ||
| upgradeDir := path.Join(upgradePath, tmpPath, "downloads") | ||
| if err != nil || len(tmpPath) == 0 || !fileOp.Stat(upgradeDir) { | ||
| if !isLangExist { | ||
| downloadLangFromRemote(fileOp) | ||
| } | ||
| if !isGeoExist { | ||
| downloadGeoFromRemote(fileOp, geoPath) | ||
| } | ||
| return | ||
| } | ||
|
|
||
| files, _ := os.ReadDir(upgradeDir) | ||
| if len(files) == 0 { | ||
| tmpPath = "no such file" | ||
| } else { | ||
| for _, item := range files { | ||
| if item.IsDir() && strings.HasPrefix(item.Name(), "1panel-") { | ||
| tmpPath = path.Join(upgradePath, tmpPath, "downloads", item.Name()) | ||
| break | ||
| } | ||
| } | ||
| } | ||
| if tmpPath == "no such file" || !fileOp.Stat(tmpPath) { | ||
| if !isLangExist { | ||
| downloadLangFromRemote(fileOp) | ||
| } | ||
| if !isGeoExist { | ||
| downloadGeoFromRemote(fileOp, geoPath) | ||
| } | ||
| return | ||
| } | ||
| if !isLangExist { | ||
| if !fileOp.Stat(path.Join(tmpPath, "lang")) { | ||
| downloadLangFromRemote(fileOp) | ||
| return | ||
| } | ||
| std, err := cmd.Execf("cp -r %s %s", path.Join(tmpPath, "lang"), "/usr/local/bin/") | ||
| if err != nil { | ||
| global.LOG.Errorf("load lang from package failed, std: %s, err: %v", std, err) | ||
| return | ||
| } | ||
| global.LOG.Info("init lang successful") | ||
| } | ||
| if !isGeoExist { | ||
| if !fileOp.Stat(path.Join(tmpPath, "GeoIP.mmdb")) { | ||
| downloadGeoFromRemote(fileOp, geoPath) | ||
| return | ||
| } | ||
| std, err := cmd.Execf("cp %s %s", path.Join(tmpPath, "GeoIP.mmdb"), path.Dir(geoPath)) | ||
| if err != nil { | ||
| global.LOG.Errorf("load geo ip from package failed, std: %s, err: %v", std, err) | ||
| return | ||
| } | ||
| global.LOG.Info("init geo ip successful") | ||
| } | ||
| } | ||
|
|
||
| func loadRestorePath(upgradeDir string) (string, error) { | ||
| if _, err := os.Stat(upgradeDir); err != nil && os.IsNotExist(err) { | ||
| return "no such file", nil | ||
| } | ||
| files, err := os.ReadDir(upgradeDir) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| var folders []string | ||
| for _, file := range files { | ||
| if file.IsDir() { | ||
| folders = append(folders, file.Name()) | ||
| } | ||
| } | ||
| if len(folders) == 0 { | ||
| return "no such file", nil | ||
| } | ||
| sort.Slice(folders, func(i, j int) bool { | ||
| return folders[i] > folders[j] | ||
| }) | ||
| return folders[0], nil | ||
| } | ||
|
|
||
| func downloadLangFromRemote(fileOp files.FileOp) { | ||
| path := fmt.Sprintf("%s/language/lang.tar.gz", global.CONF.System.RepoUrl) | ||
| if err := fileOp.DownloadFileWithProxy(path, "/usr/local/bin/lang.tar.gz"); err != nil { | ||
| global.LOG.Errorf("download lang.tar.gz failed, err: %v", err) | ||
| return | ||
| } | ||
| if !fileOp.Stat("/usr/local/bin/lang.tar.gz") { | ||
| global.LOG.Error("download lang.tar.gz failed, no such file") | ||
| return | ||
| } | ||
| std, err := cmd.Execf("tar zxvfC %s %s", "/usr/local/bin/lang.tar.gz", "/usr/local/bin/") | ||
| if err != nil { | ||
| fmt.Printf("decompress lang.tar.gz failed, std: %s, err: %v", std, err) | ||
| return | ||
| } | ||
| _ = os.Remove("/usr/local/bin/lang.tar.gz") | ||
| global.LOG.Info("download lang successful") | ||
| } | ||
| func downloadGeoFromRemote(fileOp files.FileOp, targetPath string) { | ||
| _ = os.MkdirAll(path.Dir(targetPath), os.ModePerm) | ||
| pathItem := fmt.Sprintf("%s/geo/GeoIP.mmdb", global.CONF.System.RepoUrl) | ||
| if err := fileOp.DownloadFileWithProxy(pathItem, targetPath); err != nil { | ||
| global.LOG.Errorf("download geo ip failed, err: %v", err) | ||
| return | ||
| } | ||
| global.LOG.Info("download geo ip successful") | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided code has several potential issues and areas for improvement:
Here’s an improved version of the code incorporating some of these suggestions: package lang
import (
"fmt"
"os"
"path"
"sort"
"strings"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/files"
)
var fileOp files.FileOp = files.NewFileOp()
func Init() {
initLang()
}
func initLang() {
gopath := path.Join(global.CONF.System.BaseDir, "1panel/geo/GeoIP.mmdb")
isLangExist := fileOp.Stat("/usr/local/bin/lang/zh.sh")
isGeoExist := fileOp.Stat(gopath)
if isLangExist && isGeoExist {
return
}
upgradePath := path.Join(global.CONF.System.BaseDir, "1panel/tmp/upgrade")
tmpPath, err := loadRestorePath(upgradePath)
upgradeDir := path.Join(upgradePath, tmpPath, "downloads")
if err != nil || len(tmpPath) == 0 || !fileOp.Stat(upgradeDir) {
if !isLangExist {
err = downloadLangFromRemote(path.Join(global.CONF.System.RepoUrl, "language"))
checkErrAndLog(fmt.Sprintf("download lang.tar.gz failed, err: %v"), err)
}
if !isGeoExist {
err = downloadGeoFromRemote(global.CONF.System.RepoUrl, gopath)
checkErrAndLog(fmt.Sprintf("download geo ip failed, err: %v"), err)
}
return
}
files, _ := os.ReadDir(upgradeDir)
if len(files) == 0 {
tmpPath = "no such file"
} else {
for _, item := range files {
if item.IsDir() && strings.HasPrefix(item.Name(), "1panel-") {
tmpPath = path.Join(upgradePath, tmpPath, "downloads", item.Name())
break
}
}
}
if tmpPath == "no such file" || !fileOp.Stat(tmpPath) {
if !isLangExist {
err = downloadLangFromRemote(path.Join(global.CONF.System.RepoUrl, "language"))
checkErrAndLog(fmt.Sprintf("download lang tar.gz failed, err: %v"), err)
}
if !isGeoExist {
err = downloadGeoFromRemote(global.CONF.System.RepoUrl, gopath)
checkErrAndLog(fmt.Sprintf("download GeoIP.mmdb failed, err: %v"), err)
}
return
}
if !isLangExist {
if !fileOp.Stat(path.Join(tmpPath, "lang")) {
err = downloadLangFromRemote(path.Join(global.CONF.System.RepoUrl, "language"))
if err != nil {
checkErrAndLog(fmt.Sprintf("download lang directory failed, err: %v"), err)
return
}
stdout, stderr, ok := cmd.Execf("cp -r %s /usr/local/bin/", path.Join(tmpPath, "lang"))
logOutput(stdout, stderr, ok, true)
}
}
if !isGeoExist {
if !fileOp.Stat(path.Join(tmpPath, "GeoIP.mmdb")) {
err = downloadGeoFromRemote(global.CONF.System.RepoUrl, gopath)
if err != nil {
checkErrAndLog(fmt.Sprintf("download GeoIP.mmdb failed, err: %v"), err)
return
}
stdout, stderr, ok := cmd.Execf("cp %s %s", path.Join(tmpPath, "GeoIP.mmdb"), gopath)
logOutput(stdout, stderr, ok, false)
}
}
}
func loadRestorePath(upgradePath string) (string, error) {
if _, err := os.Stat(upgradePath); err != nil && os.IsNotExist(err) {
return "", fmt.Errorf("upgrade path '%s' does not exist", upgradePath)
}
files, err := os.ReadDir(upgradePath)
if err != nil {
return "", fmt.Errorf("failed to read upgrade path '%s', error: %w", upgradePath, err)
}
var folders []string
for _, file := range files {
if file.IsDir() {
folders = append(folders, file.Name())
}
}
if len(folders) == 0 {
return "no such file", fmt.Errorf("no valid folder found in upgrade path '%s'", upgradePath)
}
sort.SliceStable(folders, func(i, j int) bool {
return folders[i] > folders[j]
})
return folders[0], nil
}
func downloadLangFromRemote(url string) error {
filePath := "/usr/local/bin/lang.tar.gz"
err := fileOp.DownloadFileWithProxy(url+"/language.lang.tar.gz.zip", filePath+".zip")
if err != nil {
deleteTemp(filePath + ".zip")
return err
}
defer deleteTemp(filePath + ".zip")
err = unzipFileIfExist(filePath + ".zip", filePath)
if err != nil {
return err
}
files, _ := os.ReadFile(filepath.Join(filePath, "files.txt"))
fileList := strings.Split(string(files), "\n\n")
for i, fileListStr := range fileList {
items := strings.Fields(strings.TrimSpace(fileListStr))
for _, item := range items {
srcFilePath := filepath.Join(filePath, item)
dstFolderPath := filepath.Join("/usr/local/bin/") + item[:strings.LastIndex(item, "_")]
os.MkdirAll(dstFolderPath, os.ModePerm)
copyFile(srcFilePath, dstFolderPath+"/"+item[strings.LastIndex(item, "_")+1:])
}
}
deleteTemp(filePath)
fmt.Println("Language package extracted successfully.")
return nil
}
func deleteTemp(suffix ...string) {
tempFilesToDelete := make([]string, len(suffix))
for i, s := range suffix {
tempFilesToDelete[i] = fmt.Sprintf("/tmp/%s", s)
}
for _, filen := range tempFilesToDelete {
// Use os.RemoveAll to clean up directories recursively
if err := os.RemoveAll(filen); err != nil {
global.Log.Warnf("Failed to delete temporary files at '%s'. Error: %v\n", filen, err)
continue
}
}
}
func copyFile(source, destination string) error {
in, err := os.Open(source)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(destination)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return nil
}
func unzipFileIfExist(zipFile, dest string) error {
exist, err := fileOp.Stat(dest + "/1panel/geo/GeoIP.mmdb")
if !exist && err == nil {
err := exec.Command("unzip", zipFile).Run()
if err != nil {
_ = os.Remove(zipFile)
return fmt.Errorf("unzip failed: %w", err)
}
_ = os.Remove(zipFile)
}
return nil
}
func checkErrAndLog(formatString string, err error) {
if err != nil {
msg := fmt.Sprintf(formatString, err)
global LOG.Errorf(msg)
}
}
func logOutput(stdout, stderr []byte, success bool, writeErrToFile bool) {
if !success && writeErrToFile {
writeFile("", ioutil.ReadAll(stderr))
}
if stdout != nil && len(stdout) > 0{
fmt.Printf("> STDOUT:\n%s\n<\n", string(stdout))
}else{
fmt.Print("No command output.\n")
}
if stderr != nil && len(stderr) > 0 {
fmt.Printf("> STDERR:\n%s\n<\n", string(stderr))
}else{
fmt.Print("No commands executed successfully.\n")
}
}Key Changes:
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,15 +4,17 @@ import ( | |
| "crypto/tls" | ||
| "encoding/gob" | ||
| "fmt" | ||
| "github.com/1Panel-dev/1Panel/backend/constant" | ||
| "github.com/1Panel-dev/1Panel/backend/i18n" | ||
| "net" | ||
| "net/http" | ||
| "os" | ||
| "path" | ||
|
|
||
| "github.com/1Panel-dev/1Panel/backend/constant" | ||
| "github.com/1Panel-dev/1Panel/backend/i18n" | ||
|
|
||
| "github.com/1Panel-dev/1Panel/backend/init/app" | ||
| "github.com/1Panel-dev/1Panel/backend/init/business" | ||
| "github.com/1Panel-dev/1Panel/backend/init/lang" | ||
|
|
||
| "github.com/1Panel-dev/1Panel/backend/cron" | ||
| "github.com/1Panel-dev/1Panel/backend/init/cache" | ||
|
|
@@ -38,6 +40,7 @@ func Start() { | |
| db.Init() | ||
| migration.Init() | ||
| app.Init() | ||
| lang.Init() | ||
| validator.Init() | ||
| gob.Register(psession.SessionUser{}) | ||
| cache.Init() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided code changes seem to be adding an additional initialization step for setting up language translations using the Here are some considerations:
Overall, these changes appear correct if they align with your project's goals related to internationalization (i18n) support and are integrated into a well-tested system of operations. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided code has several discrepancies and concerns that need to be addressed:
Incorrect Import Path: The imports of functions used in
initLangare not correctly specified within the same package.Resource Management Issues:
/usr/local/bin/lang/zh.shexists without handling any errors.Security Considerations:
fmt.Println) poses a risk if variable values are user-provided.Performance Improvements:
os.Stat()for performance improvements.Suggestions:
Correct Initialization Imports:
Error Handling:
Add detailed logging and proper error messages throughout the critical sections of your code.
Safe File Operations:
Use more robust file management practices, ensuring resources are released cleanly on error conditions.
Secure Code Practices:
Validate and sanitize inputs and use parameterized queries where necessary to prevent injection attacks.
Here's a revised version of
initLangfocusing on these points:This revision incorporates some improvements regarding security, reliability, and organization, while maintaining simplicity and readability.