mirror of https://github.com/goproxyio/goproxy
145 lines
3.5 KiB
Go
145 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/goproxyio/goproxy/module"
|
|
)
|
|
|
|
var cacheDir string
|
|
var listen string
|
|
|
|
func init() {
|
|
flag.StringVar(&listen, "listen", "0.0.0.0:8081", "service listen address")
|
|
flag.Parse()
|
|
}
|
|
|
|
func main() {
|
|
gpEnv := os.Getenv("GOPATH")
|
|
if gpEnv == "" {
|
|
panic("can not find $GOPATH")
|
|
}
|
|
fmt.Fprintf(os.Stdout, "goproxy: %s inited.\n", time.Now().Format("2006-01-02 15:04:05"))
|
|
gp := filepath.SplitList(gpEnv)
|
|
cacheDir = filepath.Join(gp[0], "pkg", "mod", "cache", "download")
|
|
if _, err := os.Stat(cacheDir); os.IsNotExist(err) {
|
|
fmt.Fprintf(os.Stdout, "goproxy: %s cache dir is not exist. %s\n", time.Now().Format("2006-01-02 15:04:05"), cacheDir)
|
|
os.MkdirAll(cacheDir, 0755)
|
|
}
|
|
http.Handle("/", mainHandler(http.FileServer(http.Dir(cacheDir))))
|
|
err := http.ListenAndServe(listen, nil)
|
|
if nil != err {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func mainHandler(inner http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintf(os.Stdout, "goproxy: %s %s download %s\n", r.RemoteAddr, time.Now().Format("2006-01-02 15:04:05"), r.URL.Path)
|
|
if _, err := os.Stat(filepath.Join(cacheDir, r.URL.Path)); err != nil {
|
|
suffix := path.Ext(r.URL.Path)
|
|
if suffix == ".info" || suffix == ".mod" || suffix == ".zip" {
|
|
mod := strings.Split(r.URL.Path, "/@v/")
|
|
if len(mod) != 2 {
|
|
ReturnBadRequest(w, fmt.Errorf("bad module path:%s", r.URL.Path))
|
|
return
|
|
}
|
|
version := strings.TrimSuffix(mod[1], suffix)
|
|
version, err = module.DecodeVersion(version)
|
|
if err != nil {
|
|
ReturnServerError(w, err)
|
|
return
|
|
}
|
|
path := strings.TrimPrefix(mod[0], "/")
|
|
path, err := module.DecodePath(path)
|
|
if err != nil {
|
|
ReturnServerError(w, err)
|
|
return
|
|
}
|
|
// ignore the error, incorrect tag may be given
|
|
// forward to inner.ServeHTTP
|
|
goGet(path, version, suffix, w, r)
|
|
}
|
|
|
|
// fetch latest version
|
|
if strings.HasSuffix(r.URL.Path, "/@latest") {
|
|
path := strings.TrimSuffix(r.URL.Path, "/@latest")
|
|
path = strings.TrimPrefix(path, "/")
|
|
path, err := module.DecodePath(path)
|
|
if err != nil {
|
|
ReturnServerError(w, err)
|
|
return
|
|
}
|
|
goGet(path, "latest", "", w, r)
|
|
}
|
|
|
|
if strings.HasSuffix(r.URL.Path, "/@v/list") {
|
|
w.Write([]byte(""))
|
|
return
|
|
}
|
|
}
|
|
inner.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func goGet(path, version, suffix string, w http.ResponseWriter, r *http.Request) error {
|
|
cmd := exec.Command("go", "get", "-d", path+"@"+version)
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stderr, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
bytesErr, err := ioutil.ReadAll(stderr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = ioutil.ReadAll(stdout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "goproxy: download %s stderr:\n%s", path, string(bytesErr))
|
|
return err
|
|
}
|
|
out := fmt.Sprintf("%s", bytesErr)
|
|
|
|
for _, line := range strings.Split(out, "\n") {
|
|
f := strings.Fields(line)
|
|
if len(f) != 4 {
|
|
continue
|
|
}
|
|
if f[1] == "downloading" && f[2] == path && f[3] != version && suffix != "" {
|
|
h := r.Host
|
|
mod := strings.Split(r.URL.Path, "/@v/")
|
|
p := fmt.Sprintf("%s/@v/%s%s", mod[0], f[3], suffix)
|
|
scheme := "http:"
|
|
if r.TLS != nil {
|
|
scheme = "https:"
|
|
}
|
|
url := fmt.Sprintf("%s//%s/%s", scheme, h, p)
|
|
http.Redirect(w, r, url, 302)
|
|
}
|
|
}
|
|
return nil
|
|
}
|