commit 0be3e70228f37c4751196979a812ea906236360b Author: 502647092 Date: Mon Oct 29 18:36:37 2018 +0800 Create & Init Porject... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e11382 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# ---> Go +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +/vendor +debug +*.exe +docker-image-sync +*.log +*.tgz \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..dc6bd32 --- /dev/null +++ b/main.go @@ -0,0 +1,182 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os/exec" + "strconv" + "strings" +) + +var ( + cache = map[string]string{} + target string + client = &http.Client{} +) + +const ( + docker = "docker" +) + +func main() { + b := flag.String("b", ":8080", "Server Listen Port") + t := flag.String("t", "registry.cn-hangzhou.aliyuncs.com/miaowoo", "Target Repo") + u := flag.String("u", "", "Target Repo UserName") + p := flag.String("p", "", "Target Repo Password") + flag.Parse() + + target = *t + + if _, err := exec.LookPath(docker); err != nil { + fmt.Printf("Error Can't Find %s Client...", docker) + return + } + + loginResult, err := exec.Command(docker, "login", *t, "-u", *u, "-p", *p).Output() + + if err != nil { + fmt.Printf("Error Can't Login To %s Username %s Password %s ...\nError: %s", *t, *u, *p, err.Error()) + return + } + + fmt.Printf(string(loginResult)) + + startServer(*b) +} + +func startServer(b string) { + http.HandleFunc("/", func(resp http.ResponseWriter, req *http.Request) { + if strings.HasPrefix(req.RequestURI, "/api") { + handleAPI(resp, req) + return + } + handleNormal(resp, req) + }) + fmt.Println("Start Server Listen On: " + b) + http.ListenAndServe(b, nil) +} + +func handleAPI(w http.ResponseWriter, r *http.Request) { + fmt.Println("[A] " + r.RequestURI) +} + +func getToken(image string) string { + resp, _ := http.Get("https://dockerauth.cn-hangzhou.aliyuncs.com/auth?service=registry.aliyuncs.com:cn-hangzhou:26842&scope=repository:miaowoo/" + image + ":pull") + var result []byte + result, _ = ioutil.ReadAll(resp.Body) + var auth map[string]string + json.Unmarshal(result, &auth) + return auth["token"] +} + +func checkMirror(image string) bool { + i := image + v := "latest" + if strings.Contains(image, ":") { + arr := strings.Split(image, ":") + i = arr[0] + v = arr[1] + } + url := fmt.Sprintf("https://registry.cn-hangzhou.aliyuncs.com/v2/miaowoo/%s/manifests/%s", i, v) + req, _ := http.NewRequest("GET", url, nil) + req.Header.Set("Authorization", "Bearer "+getToken(i)) + resp, _ := client.Do(req) + fmt.Println("[C] " + strconv.Itoa(resp.StatusCode)) + return resp.StatusCode == 200 +} + +func handleNormal(resp http.ResponseWriter, req *http.Request) { + fmt.Println("[N] " + req.RequestURI) + + if strings.Contains(req.RequestURI, ".ico") || strings.Contains(req.RequestURI, ".txt") { + resp.Write([]byte("Noop...")) + return + } + + origin := subString(req.RequestURI, 1, len(req.RequestURI)) + + if strings.Contains(origin, target) { + resp.Write([]byte("Image " + origin + " Is Self Can't Sync...")) + return + } + + if _, ok := cache[origin]; ok { + resp.Write([]byte("Image " + origin + " Is Syncing... \nProcess " + string(cache[origin]) + "... \nPlease Wait...")) + return + } + + name := strings.Replace(origin, "/", "_", -1) + + image := target + "/" + name + + out := `` + out += `

Image ` + origin + ` Is Tag to ` + image + ` And Push Success

` + + if checkMirror(name) { + out += "Alread Transfer" + } else { + cache[origin] = "0" + out += `

Transfer Log

+
+` + transferImage(origin, image) + `
+
` + delete(cache, origin) + } + out += `

You Can Use below Command To Pull...

+
+docker pull ` + image + `
+docker tag ` + image + ` ` + origin + `
+docker rmi ` + image + `
+
` + out += "" + resp.Write([]byte(out)) +} + +func transferImage(origin string, image string) string { + out := "" + cache[origin] = "10" + out += runCommand(docker, "pull", origin) + cache[origin] = "30" + out += runCommand(docker, "tag", origin, image) + cache[origin] = "50" + out += runCommand(docker, "push", image) + cache[origin] = "70" + out += runCommand(docker, "rmi", origin) + cache[origin] = "90" + out += runCommand(docker, "rmi", image) + cache[origin] = "100" + return out +} + +func runCommand(command string, args ...string) string { + result, err := exec.Command(command, args...).Output() + out := string(result) + if err != nil { + out = out + err.Error() + } + return out +} + +func subString(str string, begin, length int) (substr string) { + // 将字符串的转换成[]rune + rs := []rune(str) + lth := len(rs) + + // 简单的越界判断 + if begin < 0 { + begin = 0 + } + if begin >= lth { + begin = lth + } + end := begin + length + if end > lth { + end = lth + } + + // 返回子串 + return string(rs[begin:end]) +}