package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "os" "regexp" "strings" "github.com/mattn/go-jsonpointer" ) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World") } func main() { host := "0.0.0.0" port := os.Getenv("PORT") if port == "" { // local port = "8080" host = "127.0.0.1" } http.HandleFunc("/oembed", oEmbedHandler) http.HandleFunc("/", handler) log.Printf("Listening on port %s:%s", host, port) log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%s", host, port), nil)) } func oEmbedHandler(w http.ResponseWriter, r *http.Request) { log.Printf("Handle HTTP request %s\n", r.URL) target := r.URL.Query()["url"][0] data, err := newOEmbedData(target) if err != nil { body, _ := json.Marshal(map[string]string{"error": err.Error()}) w.WriteHeader(http.StatusNotFound) w.Header().Set("Content-Type", "application/json") w.Write(body) } else { body, _ := json.Marshal(data) w.Header().Set("Content-Type", "application/json") w.Write(body) } } type oEmbedData struct { Url string `json:"url"` Title string `json:"title"` Tags []string `json:"tags"` Description string `json:"description"` Html string `json:"html"` Published string `json:"published"` BlogUrl string `json:"blog_url"` BlogTitle string `json:"blog_title"` AuthorUrl string `json:"author_url"` AuthorName string `json:"author_name"` ProviderName string `json:"provider_name"` ProviderUrl string `json:"provider_url"` ImageUrl string `json:"image_url"` Width string `json:"width"` Height string `json:"height"` Version string `json:"version"` Type string `json:"type"` } func newOEmbedData(url string) (*oEmbedData, error) { post, err := findPost(url) if err != nil { log.Println(err.Error()) return nil, err } oEmbedData := oEmbedData{ Url: url, Title: post.Title, Description: post.Description, Tags: post.Tags, Published: post.Date, Html: buildHtml(url, post), BlogUrl: "https://blog.petitviolet.net", BlogTitle: "blog.petitviolet.net", AuthorUrl: "https://petitviolet.net", AuthorName: "petitviolet", ProviderName: "blog.petitviolet.net", ProviderUrl: "https://blog.petitviolet.net", ImageUrl: "https://s.gravatar.com/avatar/93bc8fb48f57c11e417dad9d26a2fb8a?s=480", Width: "100%", Height: "200px", Version: "1.0", Type: "rich", } return &oEmbedData, nil } type Post struct { Title string Tags []string Description string Excerpt string Date string } var urlPattern = regexp.MustCompile(`^https://blog.petitviolet.net/post/(\d{4}-\d{2}-\d{2})/(.+)$`) func findPost(url string) (*Post, error) { res := urlPattern.FindStringSubmatch(url) if len(res) != 3 { return nil, fmt.Errorf("Invalid url. url: %s", url) } pageDataPath := buildPageDatePath(res[1], res[2]) raw, err := ioutil.ReadFile(pageDataPath) if err != nil { err = fmt.Errorf("Failed to read file. file = %s, err = %s", pageDataPath, err.Error()) return nil, err } return buildPost(raw), nil } func buildHtml(url string, post *Post) string { id := strings.Replace(post.Title, " ", "-", -1) return fmt.Sprintf(`