package playground import ( "context" "crypto/md5" "fmt" "io" "net/http" "os" "strings" ) var shareURL = "https://play.golang.org/share" var cache = make(map[string]Code) // Code is a playground code type Code string func (c Code) URL() string { return fmt.Sprintf("https://play.golang.org/p/%s", c) } // Share creates a share link from text func Share(ctx context.Context, contents string) (Code, error) { return share(ctx, contents) } // ShareFile creates a share link from a file func ShareFile(ctx context.Context, path string) (Code, error) { stat, err := os.Stat(path) if err != nil { return "", fmt.Errorf("could not stat file: %w", err) } if stat.IsDir() { return "", fmt.Errorf("%s is a directory, not a file", path) } if !strings.HasSuffix(stat.Name(), ".go") { return "", fmt.Errorf("%s is not a Go file", path) } fi, err := os.Open(path) if err != nil { return "", fmt.Errorf("could not open file: %w", err) } defer fi.Close() contents, err := io.ReadAll(fi) if err != nil { return "", fmt.Errorf("could not read file: %w", err) } return share(ctx, string(contents)) } func share(ctx context.Context, contents string) (Code, error) { hash := fmt.Sprintf("%x", md5.Sum([]byte(contents))) if link, ok := cache[hash]; ok { return link, nil } req, err := http.NewRequestWithContext(ctx, http.MethodPost, shareURL, strings.NewReader(contents)) if err != nil { return "", fmt.Errorf("could not create request: %w", err) } req.Header.Set("User-Agent", "git.jojodev.com/golang/go-playground") res, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("could not create share link: %w", err) } defer res.Body.Close() b, err := io.ReadAll(res.Body) if err != nil { return "", fmt.Errorf("could not read response body: %w", err) } cache[hash] = Code(b) return cache[hash], nil }