dispatch/server/server.go

238 lines
4.8 KiB
Go
Raw Normal View History

package server
import (
"log"
"net"
"net/http"
2020-05-20 05:21:12 +00:00
"os"
2020-05-17 01:55:46 +00:00
"strconv"
2016-01-04 18:26:32 +00:00
"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/https"
2020-06-16 09:26:07 +00:00
"github.com/khlieng/dispatch/pkg/ident"
"github.com/khlieng/dispatch/pkg/session"
2015-12-11 03:35:48 +00:00
"github.com/khlieng/dispatch/storage"
)
2019-01-23 06:34:39 +00:00
var channelIndexes = storage.NewChannelIndexManager()
type Dispatch struct {
Store storage.Store
SessionStore storage.SessionStore
2018-12-11 09:51:20 +00:00
cfg *config.Config
upgrader websocket.Upgrader
states *stateStore
2020-06-16 09:26:07 +00:00
identd *ident.Server
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() {
2020-06-16 09:26:07 +00:00
cfg := d.Config()
d.upgrader = websocket.Upgrader{
2015-05-01 22:20:22 +00:00
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
2020-06-16 09:26:07 +00:00
if cfg.Dev {
d.upgrader.CheckOrigin = func(r *http.Request) bool {
return true
}
}
2020-06-16 09:26:07 +00:00
if cfg.Identd {
d.identd = ident.NewServer()
d.identd.Addr = net.JoinHostPort(cfg.Address, "113")
2020-06-16 09:26:07 +00:00
go d.identd.Listen()
}
session.CookieName = "sid"
d.states = newStateStore(d.SessionStore)
go d.states.run()
d.loadUsers()
d.initFileServer()
d.serveHTTP()
}
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) {
state := NewState(user, d)
d.states.set(state)
go state.run()
2020-06-15 08:58:51 +00:00
networks, err := user.Networks()
if err != nil {
log.Fatal(err)
}
2020-06-15 08:58:51 +00:00
channels, err := user.Channels()
if err != nil {
log.Fatal(err)
}
2020-06-15 08:58:51 +00:00
for _, network := range networks {
i := connectIRC(network, state, user.GetLastIP())
var joining []string
for _, channel := range channels {
2020-06-15 08:58:51 +00:00
if channel.Network == network.Host {
network.AddChannel(network.NewChannel(channel.Name))
joining = append(joining, channel.Name)
}
}
i.Join(joining...)
}
}
func (d *Dispatch) serveHTTP() {
2018-12-11 09:51:20 +00:00
cfg := d.Config()
2018-12-11 09:51:20 +00:00
port := cfg.Port
if cfg.Dev {
// The node dev server will proxy index page requests and
// websocket connections to this port
port = "1337"
}
if cfg.HTTPS.Enabled {
log.Println("[HTTP] Listening on port", port, "(HTTPS Redirect)")
log.Println("[HTTPS] Listening on port", cfg.HTTPS.Port)
2016-01-04 18:26:32 +00:00
} else {
log.Println("[HTTP] Listening on port", port)
}
log.Fatal(https.Serve(d, https.Config{
Addr: cfg.Address,
PortHTTP: port,
PortHTTPS: cfg.HTTPS.Port,
HTTPOnly: !cfg.HTTPS.Enabled,
2020-04-20 01:02:15 +00:00
StoragePath: storage.Path.LetsEncrypt(),
Domain: cfg.LetsEncrypt.Domain,
Email: cfg.LetsEncrypt.Email,
Cert: cfg.HTTPS.Cert,
Key: cfg.HTTPS.Key,
}))
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" {
state := d.handleAuth(w, r, true, true)
data := d.getIndexData(r, 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)
2020-05-17 01:55:46 +00:00
} else if strings.HasPrefix(r.URL.Path, "/downloads") {
state := d.handleAuth(w, r, false, false)
if state == nil {
log.Println("[Auth] No state")
fail(w, http.StatusInternalServerError)
return
}
params := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
if len(params) == 3 {
userID, err := strconv.ParseUint(params[1], 10, 64)
if err != nil {
fail(w, http.StatusBadRequest)
}
if userID != state.user.ID {
fail(w, http.StatusUnauthorized)
}
filename := params[2]
w.Header().Set("Content-Disposition", "attachment; filename="+filename)
2020-05-20 05:21:12 +00:00
2020-06-15 08:58:51 +00:00
if pack, ok := state.pendingDCC(filename); ok {
2020-05-20 05:21:12 +00:00
state.deletePendingDCC(filename)
w.Header().Set("Content-Length", strconv.FormatUint(pack.Length, 10))
2020-06-16 01:04:27 +00:00
pack.Download(w, nil)
2020-05-20 05:21:12 +00:00
} else {
file := storage.Path.DownloadedFile(state.user.Username, filename)
http.ServeFile(w, r, file)
if d.Config().DCC.Autoget.Delete {
os.Remove(file)
}
}
2020-05-17 01:55:46 +00:00
} else {
fail(w, http.StatusNotFound)
}
} 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
}
func fail(w http.ResponseWriter, code int) {
http.Error(w, http.StatusText(code), code)
}