Skip to content

Instantly share code, notes, and snippets.

@muonoum
Last active February 17, 2021 20:33
Show Gist options
  • Select an option

  • Save muonoum/3e30eedf6b416e6e0d3bfc6424c1646f to your computer and use it in GitHub Desktop.

Select an option

Save muonoum/3e30eedf6b416e6e0d3bfc6424c1646f to your computer and use it in GitHub Desktop.
package main
import (
"net/http"
"os"
)
type fallbackFileSystem struct {
http.FileSystem
fallback string
}
func (fs *fallbackFileSystem) Open(name string) (http.File, error) {
f, err := fs.FileSystem.Open(name)
if os.IsNotExist(err) {
return fs.FileSystem.Open(fs.fallback)
}
return f, err
}
func assetsHandler() http.Handler {
assetsFileSystem := assetsFS()
return http.FileServer(
&fallbackFileSystem{
FileSystem: http.FS(assetsFileSystem),
fallback: "index.html",
})
}
// +build !dev
package main
import (
"embed"
"io/fs"
"log"
)
func init() {
log.Println("Serve embedded assets")
}
//go:embed build/frontend
var assets embed.FS
func assetsFS() fs.FS {
dir, _ := fs.Sub(assets, "build/frontend")
return dir
}
// +build dev
package main
import (
"io/fs"
"log"
"os"
)
func init() {
log.Println("Serve assets from file system")
}
func assetsFS() fs.FS {
return os.DirFS("build/frontend")
}
package main
import (
"log"
"net/http"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
Address string `default:":1234"`
Proxy Proxy `default:"/api/,http://localhost:5678"`
}
func main() {
var config Config
if err := envconfig.Process("APP", &config); err != nil {
panic(err)
}
for prefix, target := range config.Proxy {
log.Printf("Proxy %s to %s", prefix, target)
http.Handle(prefix, proxyHandler(target))
}
http.Handle("/", assetsHandler())
log.Printf("Listen on %s", config.Address)
http.ListenAndServe(config.Address, nil)
}
package main
import (
"errors"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
)
type Proxy map[string]*url.URL
func (p *Proxy) Decode(value string) error {
proxy := make(Proxy)
for _, mapping := range strings.Split(value, ";") {
parts := strings.Split(mapping, ",")
for i := range parts {
parts[i] = strings.TrimSpace(parts[i])
}
if parts[0] == "" || len(parts) != 2 {
return errors.New("bad proxy map")
}
url, err := url.Parse(parts[1])
if err != nil {
return err
}
proxy[parts[0]] = url
}
*p = proxy
return nil
}
func proxyHandler(target *url.URL) *httputil.ReverseProxy {
p := httputil.NewSingleHostReverseProxy(target)
p.FlushInterval = 100 * time.Millisecond
p.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 10 * time.Second,
}).Dial,
}
return p
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment