84 lines
1.8 KiB
Go
84 lines
1.8 KiB
Go
|
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
|
||
|
}
|