blob: b6b459acffe2767c021644c0e00f4e9068298e48 [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package play
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"strings"
"sync/atomic"
"time"
"golang.org/x/website/internal/web"
)
type playVersion struct {
Name string
Backend string
}
var playVersions atomic.Value
func playHandler(site *web.Site) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/play/" && !strings.HasPrefix(r.URL.Path, "/play/p/") || r.URL.Path == "/play/p/" {
http.Redirect(w, r, "/play/", http.StatusFound)
return
}
if r.Host == "golang.google.cn" && strings.HasPrefix(r.URL.Path, "/play/p/") {
site.ServeError(w, r, errors.New("Sorry, but shared playground snippets are not visible in China."))
return
}
if strings.HasSuffix(r.URL.Path, ".go") {
simpleProxy(w, r, "https://"+backend(r)+strings.TrimPrefix(r.URL.Path, "/play"))
return
}
site.ServePage(w, r, web.Page{
"URL": r.URL.Path,
"layout": "play",
"title": "Go Playground",
"playVersions": playVersions.Load().([]playVersion),
})
})
}
func init() {
// Default set until we get the full list from play.golang.org.
playVersions.Store([]playVersion{
{Name: "Go release", Backend: ""},
{Name: "Go previous release", Backend: "goprev"},
{Name: "Go dev branch", Backend: "gotip"},
})
go watchVersions()
}
func readVersions() (list []playVersion, err error) {
defer func() {
if e := recover(); e != nil {
list = nil
err = fmt.Errorf("readVersions: %v", e)
}
}()
client := &http.Client{
Timeout: 2 * time.Minute,
}
list = append([]playVersion(nil), playVersions.Load().([]playVersion)...)
for i, v := range list {
resp, err := client.Get("https://" + v.Backend + "play.golang.org/version")
if err != nil {
log.Printf("readVersions: %v", err)
continue
}
js, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Printf("readVersions: %v", err)
continue
}
if resp.StatusCode != 200 {
log.Printf("readVersions: %s\n%s", resp.Status, js)
continue
}
var data struct{ Name string }
if err := json.Unmarshal(js, &data); err != nil {
log.Printf("readVersions: %v", err)
continue
}
if data.Name != "" {
list[i].Name = data.Name
}
}
return list, nil
}
func watchVersions() {
for ; ; time.Sleep(1 * time.Minute) {
list, err := readVersions()
if err != nil {
log.Print(err)
continue
}
playVersions.Store(list)
}
}