dispatch/server/server.go

272 lines
5.8 KiB
Go
Raw Normal View History

package server
import (
2017-04-15 02:48:24 +00:00
"crypto/tls"
"log"
2016-01-04 18:26:32 +00:00
"net"
"net/http"
2016-01-04 18:26:32 +00:00
"net/http/httputil"
"net/url"
"strings"
2018-12-11 09:51:20 +00:00
"sync"
2016-03-01 00:51:26 +00:00
"github.com/gorilla/websocket"
2018-12-11 09:51:20 +00:00
"github.com/khlieng/dispatch/config"
"github.com/khlieng/dispatch/pkg/letsencrypt"
"github.com/khlieng/dispatch/pkg/session"
2015-12-11 03:35:48 +00:00
"github.com/khlieng/dispatch/storage"
)
var channelStore = storage.NewChannelStore()
type Dispatch struct {
Store storage.Store
SessionStore storage.SessionStore
GetMessageStore func(*storage.User) (storage.MessageStore, error)
GetMessageSearchProvider func(*storage.User) (storage.MessageSearchProvider, error)
2018-12-11 09:51:20 +00:00
cfg *config.Config
upgrader websocket.Upgrader
states *stateStore
2018-12-11 09:51:20 +00:00
lock sync.Mutex
}
func New(cfg *config.Config) *Dispatch {
return &Dispatch{
cfg: cfg,
}
}
func (d *Dispatch) Config() *config.Config {
d.lock.Lock()
cfg := d.cfg
d.lock.Unlock()
return cfg
}
func (d *Dispatch) SetConfig(cfg *config.Config) {
d.lock.Lock()
d.cfg = cfg
d.lock.Unlock()
}
func (d *Dispatch) Run() {
d.upgrader = websocket.Upgrader{
2015-05-01 22:20:22 +00:00
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
2018-12-11 09:51:20 +00:00
if d.Config().Dev {
d.upgrader.CheckOrigin = func(r *http.Request) bool {
return true
}
}
session.CookieName = "dispatch"
d.states = newStateStore(d.SessionStore)
go d.states.run()
d.loadUsers()
d.initFileServer()
d.startHTTP()
}
func (d *Dispatch) loadUsers() {
users, err := storage.LoadUsers(d.Store)
if err != nil {
log.Fatal(err)
}
log.Printf("[Init] %d users", len(users))
for _, user := range users {
go d.loadUser(user)
}
}
func (d *Dispatch) loadUser(user *storage.User) {
messageStore, err := d.GetMessageStore(user)
if err != nil {
log.Fatal(err)
}
user.SetMessageStore(messageStore)
search, err := d.GetMessageSearchProvider(user)
if err != nil {
log.Fatal(err)
}
user.SetMessageSearchProvider(search)
state := NewState(user, d)
d.states.set(state)
go state.run()
channels, err := user.GetChannels()
if err != nil {
log.Fatal(err)
}
servers, err := user.GetServers()
if err != nil {
log.Fatal(err)
}
for _, server := range servers {
i := connectIRC(server, state, user.GetLastIP())
var joining []string
for _, channel := range channels {
if channel.Server == server.Host {
joining = append(joining, channel.Name)
}
}
i.Join(joining...)
}
}
func (d *Dispatch) startHTTP() {
2018-12-11 09:51:20 +00:00
cfg := d.Config()
addr := cfg.Address
port := cfg.Port
2018-12-11 09:51:20 +00:00
if cfg.HTTPS.Enabled {
portHTTPS := cfg.HTTPS.Port
redirect := cfg.HTTPS.Redirect
2016-01-04 18:26:32 +00:00
if redirect {
2016-01-04 18:26:32 +00:00
log.Println("[HTTP] Listening on port", port, "(HTTPS Redirect)")
2018-12-11 09:51:20 +00:00
go http.ListenAndServe(net.JoinHostPort(addr, port), d.createHTTPSRedirect(portHTTPS))
2016-01-04 18:26:32 +00:00
}
server := &http.Server{
Addr: net.JoinHostPort(addr, portHTTPS),
Handler: d,
}
2018-12-11 09:51:20 +00:00
if d.certExists() {
log.Println("[HTTPS] Listening on port", portHTTPS)
2018-12-11 09:51:20 +00:00
server.ListenAndServeTLS(cfg.HTTPS.Cert, cfg.HTTPS.Key)
} else if domain := cfg.LetsEncrypt.Domain; domain != "" {
2016-01-04 18:26:32 +00:00
dir := storage.Path.LetsEncrypt()
2018-12-11 09:51:20 +00:00
email := cfg.LetsEncrypt.Email
lePort := cfg.LetsEncrypt.Port
2016-01-04 18:26:32 +00:00
2018-12-11 09:51:20 +00:00
if cfg.LetsEncrypt.Proxy && lePort != "" && (port != "80" || !redirect) {
2016-01-04 18:26:32 +00:00
log.Println("[HTTP] Listening on port 80 (Let's Encrypt Proxy))")
2018-12-11 09:51:20 +00:00
go http.ListenAndServe(net.JoinHostPort(addr, "80"), http.HandlerFunc(d.letsEncryptProxy))
2016-01-04 18:26:32 +00:00
}
le, err := letsencrypt.Run(dir, domain, email, ":"+lePort)
2016-01-04 18:26:32 +00:00
if err != nil {
log.Fatal(err)
}
2017-04-15 02:48:24 +00:00
server.TLSConfig = &tls.Config{
GetCertificate: le.GetCertificate,
2017-04-15 02:48:24 +00:00
}
log.Println("[HTTPS] Listening on port", portHTTPS)
2017-04-15 02:48:24 +00:00
log.Fatal(server.ListenAndServeTLS("", ""))
2016-01-04 18:26:32 +00:00
} else {
log.Fatal("Could not locate SSL certificate or private key")
}
} else {
2018-12-11 09:51:20 +00:00
if cfg.Dev {
// The node dev server will proxy index page requests and
// websocket connections to this port
port = "1337"
}
2016-01-04 18:26:32 +00:00
log.Println("[HTTP] Listening on port", port)
log.Fatal(http.ListenAndServe(net.JoinHostPort(addr, port), d))
2016-01-04 18:26:32 +00:00
}
}
func (d *Dispatch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
fail(w, http.StatusNotFound)
return
}
2018-11-27 11:07:48 +00:00
if r.URL.Path == "/init" {
referer, err := url.Parse(r.Header.Get("Referer"))
if err != nil {
fail(w, http.StatusInternalServerError)
return
}
state := d.handleAuth(w, r, true, true)
2018-12-11 09:51:20 +00:00
data := d.getIndexData(r, referer.EscapedPath(), state)
2018-11-27 11:07:48 +00:00
writeJSON(w, r, data)
} else if strings.HasPrefix(r.URL.Path, "/ws") {
if !websocket.IsWebSocketUpgrade(r) {
fail(w, http.StatusBadRequest)
return
}
state := d.handleAuth(w, r, false, false)
if state == nil {
log.Println("[Auth] No state")
fail(w, http.StatusInternalServerError)
return
}
d.upgradeWS(w, r, state)
} else {
d.serveFiles(w, r)
}
}
func (d *Dispatch) upgradeWS(w http.ResponseWriter, r *http.Request, state *State) {
conn, err := d.upgrader.Upgrade(w, r, w.Header())
2015-05-01 22:20:22 +00:00
if err != nil {
log.Println(err)
return
}
newWSHandler(conn, state, r).run()
2015-05-01 22:20:22 +00:00
}
2018-12-11 09:51:20 +00:00
func (d *Dispatch) createHTTPSRedirect(portHTTPS string) http.HandlerFunc {
2016-01-04 18:26:32 +00:00
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge") {
2018-12-11 09:51:20 +00:00
d.letsEncryptProxy(w, r)
2016-01-04 18:26:32 +00:00
return
}
host, _, err := net.SplitHostPort(r.Host)
if err != nil {
host = r.Host
}
2016-01-04 18:26:32 +00:00
u := url.URL{
Scheme: "https",
Host: net.JoinHostPort(host, portHTTPS),
Path: r.RequestURI,
}
w.Header().Set("Location", u.String())
w.WriteHeader(http.StatusMovedPermanently)
})
}
2018-12-11 09:51:20 +00:00
func (d *Dispatch) letsEncryptProxy(w http.ResponseWriter, r *http.Request) {
2016-01-04 18:26:32 +00:00
host, _, err := net.SplitHostPort(r.Host)
if err != nil {
host = r.Host
}
2016-01-04 18:26:32 +00:00
upstream := &url.URL{
Scheme: "http",
2018-12-11 09:51:20 +00:00
Host: net.JoinHostPort(host, d.Config().LetsEncrypt.Port),
2016-01-04 18:26:32 +00:00
}
httputil.NewSingleHostReverseProxy(upstream).ServeHTTP(w, r)
}
func fail(w http.ResponseWriter, code int) {
http.Error(w, http.StatusText(code), code)
}