package goxy import ( "crypto/tls" "encoding/json" "net/http" "net/http/httputil" "net/url" "os" "strings" ) type Server struct { DataFile string Route http.Server } func NewServer(fname string) (*Server, error) { r := make(Route) s := http.Server{TLSConfig: &tls.Config{GetCertificate: r.GetCertificate}} server := &Server{Route: r, Server: s, DataFile: fname} server.Load() Register(server) return server, server.Restore() } // Save routes to persistent file func (s Server) Save() error { if s.DataFile == "" { return nil } fd, err := os.Create(s.DataFile) if err != nil { return err } defer fd.Close() return json.NewEncoder(fd).Encode(s.Route) } // Load routes from persistent file func (s *Server) Load() error { if s.DataFile == "" { return nil } fd, err := os.Open(s.DataFile) if err != nil { return err } defer fd.Close() return json.NewDecoder(fd).Decode(&s.Route) } // Restore and update routes from in-memory state func (s *Server) Restore() error { mux := http.NewServeMux() for k, v := range s.Route { if v.Cert != nil && v.Key != nil { cert, err := tls.X509KeyPair(v.Cert, v.Key) if err != nil { return err } v.cert = &cert s.Route[k] = v } up, err := url.Parse(v.Upstream) if err != nil { return err } if !strings.Contains(v.Host, "/") { v.Host += "/" } switch up.Scheme { case "ws": mux.Handle(v.Host, NewWebSocketProxy(up)) default: mux.Handle(v.Host, httputil.NewSingleHostReverseProxy(up)) } } s.Server.Handler = mux return nil } func (s *Server) Start() error { errc := make(chan error) go func() { errc <- s.ListenAndServe() }() go func() { errc <- s.ListenAndServeTLS("", "") }() go func() { errc <- http.ListenAndServe(":http-alt", nil) }() return <-errc }