mirror of
https://github.com/schollz/cowyo.git
synced 2023-08-10 21:13:00 +03:00
111 lines
3.4 KiB
Go
111 lines
3.4 KiB
Go
// Package openutil displays Markdown or HTML in a new browser tab.
|
||
package openutil
|
||
|
||
import (
|
||
"log"
|
||
"net"
|
||
"net/http"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/shurcooL/github_flavored_markdown/gfmstyle"
|
||
"github.com/shurcooL/go/gfmutil"
|
||
"github.com/shurcooL/go/open"
|
||
)
|
||
|
||
// DisplayMarkdownInBrowser displays given Markdown in a new browser window/tab.
|
||
func DisplayMarkdownInBrowser(markdown []byte) {
|
||
stopServerChan := make(chan struct{})
|
||
|
||
handler := func(w http.ResponseWriter, req *http.Request) {
|
||
gfmutil.WriteGitHubFlavoredMarkdownViaLocal(w, markdown)
|
||
|
||
// TODO: A better way to fix: /assets/gfm/gfm.css Failed to load resource: net::ERR_CONNECTION_REFUSED.
|
||
// HACK: Give some time for other assets to finish loading.
|
||
go func() {
|
||
time.Sleep(1 * time.Second)
|
||
stopServerChan <- struct{}{}
|
||
}()
|
||
}
|
||
|
||
http.HandleFunc("/index", handler)
|
||
http.Handle("/assets/gfm/", http.StripPrefix("/assets/gfm", http.FileServer(gfmstyle.Assets))) // Serve the "/assets/gfm/gfm.css" file.
|
||
http.Handle("/favicon.ico", http.NotFoundHandler())
|
||
|
||
// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
|
||
// TODO: Consider using httptest.NewServer.
|
||
open.Open("http://localhost:7044/index")
|
||
|
||
err := httpstoppable۰ListenAndServe("localhost:7044", nil, stopServerChan)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
}
|
||
|
||
// DisplayHTMLInBrowser displays given html page in a new browser window/tab.
|
||
// query can be empty, otherwise it should begin with "?" like "?key=value".
|
||
func DisplayHTMLInBrowser(mux *http.ServeMux, stopServerChan <-chan struct{}, query string) {
|
||
// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
|
||
open.Open("http://localhost:7044/index" + query)
|
||
|
||
err := httpstoppable۰ListenAndServe("localhost:7044", mux, stopServerChan)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
}
|
||
|
||
// ListenAndServe listens on the TCP network address addr
|
||
// and then calls Serve with handler to handle requests
|
||
// on incoming connections.
|
||
// Accepted connections are configured to enable TCP keep-alives.
|
||
// Handler is typically nil, in which case the http.DefaultServeMux is
|
||
// used.
|
||
//
|
||
// When receiving from stop unblocks (because it's closed or a value is sent),
|
||
// listener is closed and ListenAndServe returns with nil error.
|
||
// Otherise, it always returns a non-nil error.
|
||
//
|
||
// Deprecated: Go 1.8 added native support for stopping a server in net/http.
|
||
// net/http should be used instead. This copied function will be removed soon.
|
||
func httpstoppable۰ListenAndServe(addr string, handler http.Handler, stop <-chan struct{}) error {
|
||
srv := &http.Server{Addr: addr, Handler: handler}
|
||
if addr == "" {
|
||
addr = ":http"
|
||
}
|
||
ln, err := net.Listen("tcp", addr)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
go func() {
|
||
<-stop
|
||
err := ln.Close()
|
||
if err != nil {
|
||
log.Println("httpstoppable.ListenAndServe: error closing listener:", err)
|
||
}
|
||
}()
|
||
err = srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
|
||
switch { // Serve always returns a non-nil error.
|
||
case strings.Contains(err.Error(), "use of closed network connection"):
|
||
return nil
|
||
default:
|
||
return err
|
||
}
|
||
}
|
||
|
||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||
// connections. It's used by ListenAndServe so dead TCP connections
|
||
// (e.g. closing laptop mid-download) eventually go away.
|
||
type tcpKeepAliveListener struct {
|
||
*net.TCPListener
|
||
}
|
||
|
||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||
tc, err := ln.AcceptTCP()
|
||
if err != nil {
|
||
return
|
||
}
|
||
tc.SetKeepAlive(true)
|
||
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||
return tc, nil
|
||
}
|