Pass in config struct
This commit is contained in:
parent
8f1105bc59
commit
71f79fd84e
@ -5,10 +5,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/khlieng/dispatch/assets"
|
"github.com/khlieng/dispatch/assets"
|
||||||
|
"github.com/khlieng/dispatch/config"
|
||||||
"github.com/khlieng/dispatch/server"
|
"github.com/khlieng/dispatch/server"
|
||||||
"github.com/khlieng/dispatch/storage"
|
"github.com/khlieng/dispatch/storage"
|
||||||
"github.com/khlieng/dispatch/storage/bleve"
|
"github.com/khlieng/dispatch/storage/bleve"
|
||||||
@ -36,34 +35,18 @@ var rootCmd = &cobra.Command{
|
|||||||
Use: "dispatch",
|
Use: "dispatch",
|
||||||
Short: "Web-based IRC client in Go.",
|
Short: "Web-based IRC client in Go.",
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
if v, _ := cmd.Flags().GetBool("version"); v {
|
if viper.GetBool("version") {
|
||||||
printVersion()
|
printVersion()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Use == "dispatch" {
|
if cmd == cmd.Root() {
|
||||||
fmt.Printf(logo, version.Tag, version.Commit, version.Date)
|
fmt.Printf(logo, version.Tag, version.Commit, version.Date)
|
||||||
}
|
}
|
||||||
|
|
||||||
storage.Initialize(viper.GetString("dir"))
|
storage.Initialize(viper.GetString("dir"))
|
||||||
|
|
||||||
initConfig(storage.Path.Config(), viper.GetBool("reset_config"))
|
initConfig(storage.Path.Config(), viper.GetBool("reset-config"))
|
||||||
|
|
||||||
viper.SetConfigName("config")
|
|
||||||
viper.AddConfigPath(storage.Path.Root())
|
|
||||||
viper.ReadInConfig()
|
|
||||||
|
|
||||||
viper.WatchConfig()
|
|
||||||
|
|
||||||
prev := time.Now()
|
|
||||||
viper.OnConfigChange(func(e fsnotify.Event) {
|
|
||||||
now := time.Now()
|
|
||||||
// fsnotify sometimes fires twice
|
|
||||||
if now.Sub(prev) > time.Second {
|
|
||||||
log.Println("New config loaded")
|
|
||||||
prev = now
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
@ -78,19 +61,28 @@ var rootCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
srv := server.Dispatch{
|
cfg, cfgUpdated := config.LoadConfig()
|
||||||
Store: db,
|
dispatch := server.New(cfg)
|
||||||
SessionStore: db,
|
|
||||||
|
|
||||||
GetMessageStore: func(user *storage.User) (storage.MessageStore, error) {
|
go func() {
|
||||||
return boltdb.New(storage.Path.Log(user.Username))
|
for {
|
||||||
},
|
dispatch.SetConfig(<-cfgUpdated)
|
||||||
GetMessageSearchProvider: func(user *storage.User) (storage.MessageSearchProvider, error) {
|
log.Println("New config loaded")
|
||||||
return bleve.New(storage.Path.Index(user.Username))
|
}
|
||||||
},
|
}()
|
||||||
|
|
||||||
|
dispatch.Store = db
|
||||||
|
dispatch.SessionStore = db
|
||||||
|
|
||||||
|
dispatch.GetMessageStore = func(user *storage.User) (storage.MessageStore, error) {
|
||||||
|
return boltdb.New(storage.Path.Log(user.Username))
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.Run()
|
dispatch.GetMessageSearchProvider = func(user *storage.User) (storage.MessageSearchProvider, error) {
|
||||||
|
return bleve.New(storage.Path.Index(user.Username))
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.Run()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,14 +102,11 @@ func init() {
|
|||||||
rootCmd.Flags().Bool("dev", false, "development mode")
|
rootCmd.Flags().Bool("dev", false, "development mode")
|
||||||
rootCmd.Flags().BoolP("version", "v", false, "show version")
|
rootCmd.Flags().BoolP("version", "v", false, "show version")
|
||||||
|
|
||||||
viper.BindPFlag("dir", rootCmd.PersistentFlags().Lookup("dir"))
|
viper.BindPFlags(rootCmd.PersistentFlags())
|
||||||
viper.BindPFlag("reset_config", rootCmd.PersistentFlags().Lookup("reset-config"))
|
viper.BindPFlags(rootCmd.Flags())
|
||||||
viper.BindPFlag("address", rootCmd.Flags().Lookup("address"))
|
|
||||||
viper.BindPFlag("port", rootCmd.Flags().Lookup("port"))
|
|
||||||
viper.BindPFlag("dev", rootCmd.Flags().Lookup("dev"))
|
|
||||||
|
|
||||||
viper.SetDefault("hexIP", false)
|
viper.SetDefault("hexIP", false)
|
||||||
viper.SetDefault("verify_client_certificates", true)
|
viper.SetDefault("verify_certificates", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig(configPath string, overwrite bool) {
|
func initConfig(configPath string, overwrite bool) {
|
||||||
|
84
config/config.go
Normal file
84
config/config.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"github.com/khlieng/dispatch/storage"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Address string
|
||||||
|
Port string
|
||||||
|
Dev bool
|
||||||
|
HexIP bool
|
||||||
|
VerifyCertificates bool `mapstructure:"verify_certificates"`
|
||||||
|
Defaults *Defaults
|
||||||
|
HTTPS *HTTPS
|
||||||
|
LetsEncrypt *LetsEncrypt
|
||||||
|
}
|
||||||
|
|
||||||
|
type Defaults struct {
|
||||||
|
Name string
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
Channels []string
|
||||||
|
Password string
|
||||||
|
SSL bool
|
||||||
|
ReadOnly bool
|
||||||
|
ShowDetails bool `mapstructure:"show_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPS struct {
|
||||||
|
Enabled bool
|
||||||
|
Port string
|
||||||
|
Redirect bool
|
||||||
|
Cert string
|
||||||
|
Key string
|
||||||
|
HSTS *HSTS
|
||||||
|
}
|
||||||
|
|
||||||
|
type HSTS struct {
|
||||||
|
Enabled bool
|
||||||
|
MaxAge string `mapstructure:"max_age"`
|
||||||
|
IncludeSubdomains bool `mapstructure:"include_subdomains"`
|
||||||
|
Preload bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type LetsEncrypt struct {
|
||||||
|
Domain string
|
||||||
|
Email string
|
||||||
|
Port string
|
||||||
|
Proxy bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() (*Config, chan *Config) {
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.AddConfigPath(storage.Path.Root())
|
||||||
|
viper.ReadInConfig()
|
||||||
|
|
||||||
|
config := &Config{}
|
||||||
|
viper.Unmarshal(config)
|
||||||
|
|
||||||
|
viper.WatchConfig()
|
||||||
|
|
||||||
|
configCh := make(chan *Config, 1)
|
||||||
|
|
||||||
|
prev := time.Now()
|
||||||
|
viper.OnConfigChange(func(e fsnotify.Event) {
|
||||||
|
now := time.Now()
|
||||||
|
// fsnotify sometimes fires twice
|
||||||
|
if now.Sub(prev) > time.Second {
|
||||||
|
config := &Config{}
|
||||||
|
err := viper.Unmarshal(config)
|
||||||
|
if err == nil {
|
||||||
|
configCh <- config
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = now
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return config, configCh
|
||||||
|
}
|
@ -5,9 +5,9 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/khlieng/dispatch/config"
|
||||||
"github.com/khlieng/dispatch/storage"
|
"github.com/khlieng/dispatch/storage"
|
||||||
"github.com/khlieng/dispatch/version"
|
"github.com/khlieng/dispatch/version"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type connectDefaults struct {
|
type connectDefaults struct {
|
||||||
@ -28,7 +28,7 @@ type dispatchVersion struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type indexData struct {
|
type indexData struct {
|
||||||
Defaults connectDefaults
|
Defaults *config.Defaults
|
||||||
Servers []Server
|
Servers []Server
|
||||||
Channels []*storage.Channel
|
Channels []*storage.Channel
|
||||||
HexIP bool
|
HexIP bool
|
||||||
@ -43,9 +43,12 @@ type indexData struct {
|
|||||||
Messages *Messages
|
Messages *Messages
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIndexData(r *http.Request, path string, state *State) *indexData {
|
func (d *Dispatch) getIndexData(r *http.Request, path string, state *State) *indexData {
|
||||||
|
cfg := d.Config()
|
||||||
|
|
||||||
data := indexData{
|
data := indexData{
|
||||||
HexIP: viper.GetBool("hexIP"),
|
Defaults: cfg.Defaults,
|
||||||
|
HexIP: cfg.HexIP,
|
||||||
Version: dispatchVersion{
|
Version: dispatchVersion{
|
||||||
Tag: version.Tag,
|
Tag: version.Tag,
|
||||||
Commit: version.Commit,
|
Commit: version.Commit,
|
||||||
@ -53,15 +56,8 @@ func getIndexData(r *http.Request, path string, state *State) *indexData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Defaults = connectDefaults{
|
if data.Defaults.Password != "" {
|
||||||
Name: viper.GetString("defaults.name"),
|
data.Defaults.Password = "******"
|
||||||
Host: viper.GetString("defaults.host"),
|
|
||||||
Port: viper.GetInt("defaults.port"),
|
|
||||||
Channels: viper.GetStringSlice("defaults.channels"),
|
|
||||||
Password: viper.GetString("defaults.password") != "",
|
|
||||||
SSL: viper.GetBool("defaults.ssl"),
|
|
||||||
ReadOnly: viper.GetBool("defaults.readonly"),
|
|
||||||
ShowDetails: viper.GetBool("defaults.show_details"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if state == nil {
|
if state == nil {
|
||||||
|
@ -4,6 +4,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
json "encoding/json"
|
json "encoding/json"
|
||||||
|
config "github.com/khlieng/dispatch/config"
|
||||||
storage "github.com/khlieng/dispatch/storage"
|
storage "github.com/khlieng/dispatch/storage"
|
||||||
easyjson "github.com/mailru/easyjson"
|
easyjson "github.com/mailru/easyjson"
|
||||||
jlexer "github.com/mailru/easyjson/jlexer"
|
jlexer "github.com/mailru/easyjson/jlexer"
|
||||||
@ -38,8 +39,14 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer(in *jlexer.Lexer, out
|
|||||||
}
|
}
|
||||||
switch key {
|
switch key {
|
||||||
case "defaults":
|
case "defaults":
|
||||||
if data := in.Raw(); in.Ok() {
|
if in.IsNull() {
|
||||||
in.AddError((out.Defaults).UnmarshalJSON(data))
|
in.Skip()
|
||||||
|
out.Defaults = nil
|
||||||
|
} else {
|
||||||
|
if out.Defaults == nil {
|
||||||
|
out.Defaults = new(config.Defaults)
|
||||||
|
}
|
||||||
|
easyjson7e607aefDecodeGithubComKhliengDispatchConfig(in, &*out.Defaults)
|
||||||
}
|
}
|
||||||
case "servers":
|
case "servers":
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
@ -153,7 +160,7 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
|||||||
out.RawByte('{')
|
out.RawByte('{')
|
||||||
first := true
|
first := true
|
||||||
_ = first
|
_ = first
|
||||||
if true {
|
if in.Defaults != nil {
|
||||||
const prefix string = ",\"defaults\":"
|
const prefix string = ",\"defaults\":"
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
@ -161,7 +168,7 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
|||||||
} else {
|
} else {
|
||||||
out.RawString(prefix)
|
out.RawString(prefix)
|
||||||
}
|
}
|
||||||
out.Raw((in.Defaults).MarshalJSON())
|
easyjson7e607aefEncodeGithubComKhliengDispatchConfig(out, *in.Defaults)
|
||||||
}
|
}
|
||||||
if len(in.Servers) != 0 {
|
if len(in.Servers) != 0 {
|
||||||
const prefix string = ",\"servers\":"
|
const prefix string = ",\"servers\":"
|
||||||
@ -352,6 +359,167 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchStorage(out *jwriter.Writer,
|
|||||||
}
|
}
|
||||||
out.RawByte('}')
|
out.RawByte('}')
|
||||||
}
|
}
|
||||||
|
func easyjson7e607aefDecodeGithubComKhliengDispatchConfig(in *jlexer.Lexer, out *config.Defaults) {
|
||||||
|
isTopLevel := in.IsStart()
|
||||||
|
if in.IsNull() {
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
in.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
in.Delim('{')
|
||||||
|
for !in.IsDelim('}') {
|
||||||
|
key := in.UnsafeString()
|
||||||
|
in.WantColon()
|
||||||
|
if in.IsNull() {
|
||||||
|
in.Skip()
|
||||||
|
in.WantComma()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch key {
|
||||||
|
case "name":
|
||||||
|
out.Name = string(in.String())
|
||||||
|
case "host":
|
||||||
|
out.Host = string(in.String())
|
||||||
|
case "port":
|
||||||
|
out.Port = int(in.Int())
|
||||||
|
case "channels":
|
||||||
|
if in.IsNull() {
|
||||||
|
in.Skip()
|
||||||
|
out.Channels = nil
|
||||||
|
} else {
|
||||||
|
in.Delim('[')
|
||||||
|
if out.Channels == nil {
|
||||||
|
if !in.IsDelim(']') {
|
||||||
|
out.Channels = make([]string, 0, 4)
|
||||||
|
} else {
|
||||||
|
out.Channels = []string{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Channels = (out.Channels)[:0]
|
||||||
|
}
|
||||||
|
for !in.IsDelim(']') {
|
||||||
|
var v7 string
|
||||||
|
v7 = string(in.String())
|
||||||
|
out.Channels = append(out.Channels, v7)
|
||||||
|
in.WantComma()
|
||||||
|
}
|
||||||
|
in.Delim(']')
|
||||||
|
}
|
||||||
|
case "password":
|
||||||
|
out.Password = string(in.String())
|
||||||
|
case "ssl":
|
||||||
|
out.SSL = bool(in.Bool())
|
||||||
|
case "readOnly":
|
||||||
|
out.ReadOnly = bool(in.Bool())
|
||||||
|
case "showDetails":
|
||||||
|
out.ShowDetails = bool(in.Bool())
|
||||||
|
default:
|
||||||
|
in.SkipRecursive()
|
||||||
|
}
|
||||||
|
in.WantComma()
|
||||||
|
}
|
||||||
|
in.Delim('}')
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func easyjson7e607aefEncodeGithubComKhliengDispatchConfig(out *jwriter.Writer, in config.Defaults) {
|
||||||
|
out.RawByte('{')
|
||||||
|
first := true
|
||||||
|
_ = first
|
||||||
|
if in.Name != "" {
|
||||||
|
const prefix string = ",\"name\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.String(string(in.Name))
|
||||||
|
}
|
||||||
|
if in.Host != "" {
|
||||||
|
const prefix string = ",\"host\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.String(string(in.Host))
|
||||||
|
}
|
||||||
|
if in.Port != 0 {
|
||||||
|
const prefix string = ",\"port\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Int(int(in.Port))
|
||||||
|
}
|
||||||
|
if len(in.Channels) != 0 {
|
||||||
|
const prefix string = ",\"channels\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
out.RawByte('[')
|
||||||
|
for v8, v9 := range in.Channels {
|
||||||
|
if v8 > 0 {
|
||||||
|
out.RawByte(',')
|
||||||
|
}
|
||||||
|
out.String(string(v9))
|
||||||
|
}
|
||||||
|
out.RawByte(']')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Password != "" {
|
||||||
|
const prefix string = ",\"password\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.String(string(in.Password))
|
||||||
|
}
|
||||||
|
if in.SSL {
|
||||||
|
const prefix string = ",\"ssl\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.SSL))
|
||||||
|
}
|
||||||
|
if in.ReadOnly {
|
||||||
|
const prefix string = ",\"readOnly\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.ReadOnly))
|
||||||
|
}
|
||||||
|
if in.ShowDetails {
|
||||||
|
const prefix string = ",\"showDetails\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.ShowDetails))
|
||||||
|
}
|
||||||
|
out.RawByte('}')
|
||||||
|
}
|
||||||
func easyjson7e607aefDecodeGithubComKhliengDispatchServer1(in *jlexer.Lexer, out *dispatchVersion) {
|
func easyjson7e607aefDecodeGithubComKhliengDispatchServer1(in *jlexer.Lexer, out *dispatchVersion) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
@ -488,9 +656,9 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer2(in *jlexer.Lexer, out
|
|||||||
out.Channels = (out.Channels)[:0]
|
out.Channels = (out.Channels)[:0]
|
||||||
}
|
}
|
||||||
for !in.IsDelim(']') {
|
for !in.IsDelim(']') {
|
||||||
var v7 string
|
var v10 string
|
||||||
v7 = string(in.String())
|
v10 = string(in.String())
|
||||||
out.Channels = append(out.Channels, v7)
|
out.Channels = append(out.Channels, v10)
|
||||||
in.WantComma()
|
in.WantComma()
|
||||||
}
|
}
|
||||||
in.Delim(']')
|
in.Delim(']')
|
||||||
@ -557,11 +725,11 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer2(out *jwriter.Writer,
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
out.RawByte('[')
|
out.RawByte('[')
|
||||||
for v8, v9 := range in.Channels {
|
for v11, v12 := range in.Channels {
|
||||||
if v8 > 0 {
|
if v11 > 0 {
|
||||||
out.RawByte(',')
|
out.RawByte(',')
|
||||||
}
|
}
|
||||||
out.String(string(v9))
|
out.String(string(v12))
|
||||||
}
|
}
|
||||||
out.RawByte(']')
|
out.RawByte(']')
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/khlieng/dispatch/pkg/irc"
|
"github.com/khlieng/dispatch/pkg/irc"
|
||||||
"github.com/khlieng/dispatch/storage"
|
"github.com/khlieng/dispatch/storage"
|
||||||
)
|
)
|
||||||
@ -38,7 +36,9 @@ func connectIRC(server *storage.Server, state *State, srcIP []byte) *irc.Client
|
|||||||
address = net.JoinHostPort(server.Host, server.Port)
|
address = net.JoinHostPort(server.Host, server.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viper.GetBool("hexIP") {
|
cfg := state.srv.Config()
|
||||||
|
|
||||||
|
if cfg.HexIP {
|
||||||
i.Username = hex.EncodeToString(srcIP)
|
i.Username = hex.EncodeToString(srcIP)
|
||||||
} else if i.Username == "" {
|
} else if i.Username == "" {
|
||||||
i.Username = server.Nick
|
i.Username = server.Nick
|
||||||
@ -49,16 +49,16 @@ func connectIRC(server *storage.Server, state *State, srcIP []byte) *irc.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
if server.Password == "" &&
|
if server.Password == "" &&
|
||||||
viper.GetString("defaults.password") != "" &&
|
cfg.Defaults.Password != "" &&
|
||||||
address == viper.GetString("defaults.host") {
|
address == cfg.Defaults.Host {
|
||||||
i.Password = viper.GetString("defaults.password")
|
i.Password = cfg.Defaults.Password
|
||||||
} else {
|
} else {
|
||||||
i.Password = server.Password
|
i.Password = server.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.TLS {
|
if i.TLS {
|
||||||
i.TLSConfig = &tls.Config{
|
i.TLSConfig = &tls.Config{
|
||||||
InsecureSkipVerify: !viper.GetBool("verify_certificates"),
|
InsecureSkipVerify: !cfg.VerifyCertificates,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert := state.user.GetCertificate(); cert != nil {
|
if cert := state.user.GetCertificate(); cert != nil {
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
|
|
||||||
"github.com/dsnet/compress/brotli"
|
"github.com/dsnet/compress/brotli"
|
||||||
"github.com/khlieng/dispatch/assets"
|
"github.com/khlieng/dispatch/assets"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const longCacheControl = "public, max-age=31536000, immutable"
|
const longCacheControl = "public, max-age=31536000, immutable"
|
||||||
@ -73,7 +72,9 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (d *Dispatch) initFileServer() {
|
func (d *Dispatch) initFileServer() {
|
||||||
if viper.GetBool("dev") {
|
cfg := d.Config()
|
||||||
|
|
||||||
|
if cfg.Dev {
|
||||||
indexScripts = []string{"boot.js", "main.js"}
|
indexScripts = []string{"boot.js", "main.js"}
|
||||||
} else {
|
} else {
|
||||||
bootloader := decompressedAsset(findAssetName("boot*.js"))
|
bootloader := decompressedAsset(findAssetName("boot*.js"))
|
||||||
@ -149,13 +150,13 @@ workbox.precaching.precacheAndRoute([{
|
|||||||
}]);
|
}]);
|
||||||
workbox.routing.registerNavigationRoute('/');`)...)
|
workbox.routing.registerNavigationRoute('/');`)...)
|
||||||
|
|
||||||
if viper.GetBool("https.hsts.enabled") && viper.GetBool("https.enabled") {
|
if cfg.HTTPS.HSTS.Enabled && cfg.HTTPS.Enabled {
|
||||||
hstsHeader = "max-age=" + viper.GetString("https.hsts.max_age")
|
hstsHeader = "max-age=" + cfg.HTTPS.HSTS.MaxAge
|
||||||
|
|
||||||
if viper.GetBool("https.hsts.include_subdomains") {
|
if cfg.HTTPS.HSTS.IncludeSubdomains {
|
||||||
hstsHeader += "; includeSubDomains"
|
hstsHeader += "; includeSubDomains"
|
||||||
}
|
}
|
||||||
if viper.GetBool("https.hsts.preload") {
|
if cfg.HTTPS.HSTS.Preload {
|
||||||
hstsHeader += "; preload"
|
hstsHeader += "; preload"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,13 @@ import (
|
|||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/khlieng/dispatch/config"
|
||||||
"github.com/khlieng/dispatch/pkg/letsencrypt"
|
"github.com/khlieng/dispatch/pkg/letsencrypt"
|
||||||
"github.com/khlieng/dispatch/pkg/session"
|
"github.com/khlieng/dispatch/pkg/session"
|
||||||
"github.com/khlieng/dispatch/storage"
|
"github.com/khlieng/dispatch/storage"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var channelStore = storage.NewChannelStore()
|
var channelStore = storage.NewChannelStore()
|
||||||
@ -25,8 +26,29 @@ type Dispatch struct {
|
|||||||
GetMessageStore func(*storage.User) (storage.MessageStore, error)
|
GetMessageStore func(*storage.User) (storage.MessageStore, error)
|
||||||
GetMessageSearchProvider func(*storage.User) (storage.MessageSearchProvider, error)
|
GetMessageSearchProvider func(*storage.User) (storage.MessageSearchProvider, error)
|
||||||
|
|
||||||
|
cfg *config.Config
|
||||||
upgrader websocket.Upgrader
|
upgrader websocket.Upgrader
|
||||||
states *stateStore
|
states *stateStore
|
||||||
|
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() {
|
func (d *Dispatch) Run() {
|
||||||
@ -35,7 +57,7 @@ func (d *Dispatch) Run() {
|
|||||||
WriteBufferSize: 1024,
|
WriteBufferSize: 1024,
|
||||||
}
|
}
|
||||||
|
|
||||||
if viper.GetBool("dev") {
|
if d.Config().Dev {
|
||||||
d.upgrader.CheckOrigin = func(r *http.Request) bool {
|
d.upgrader.CheckOrigin = func(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -105,16 +127,17 @@ func (d *Dispatch) loadUser(user *storage.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatch) startHTTP() {
|
func (d *Dispatch) startHTTP() {
|
||||||
addr := viper.GetString("address")
|
cfg := d.Config()
|
||||||
port := viper.GetString("port")
|
addr := cfg.Address
|
||||||
|
port := cfg.Port
|
||||||
|
|
||||||
if viper.GetBool("https.enabled") {
|
if cfg.HTTPS.Enabled {
|
||||||
portHTTPS := viper.GetString("https.port")
|
portHTTPS := cfg.HTTPS.Port
|
||||||
redirect := viper.GetBool("https.redirect")
|
redirect := cfg.HTTPS.Redirect
|
||||||
|
|
||||||
if redirect {
|
if redirect {
|
||||||
log.Println("[HTTP] Listening on port", port, "(HTTPS Redirect)")
|
log.Println("[HTTP] Listening on port", port, "(HTTPS Redirect)")
|
||||||
go http.ListenAndServe(net.JoinHostPort(addr, port), createHTTPSRedirect(portHTTPS))
|
go http.ListenAndServe(net.JoinHostPort(addr, port), d.createHTTPSRedirect(portHTTPS))
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
@ -122,17 +145,17 @@ func (d *Dispatch) startHTTP() {
|
|||||||
Handler: d,
|
Handler: d,
|
||||||
}
|
}
|
||||||
|
|
||||||
if certExists() {
|
if d.certExists() {
|
||||||
log.Println("[HTTPS] Listening on port", portHTTPS)
|
log.Println("[HTTPS] Listening on port", portHTTPS)
|
||||||
server.ListenAndServeTLS(viper.GetString("https.cert"), viper.GetString("https.key"))
|
server.ListenAndServeTLS(cfg.HTTPS.Cert, cfg.HTTPS.Key)
|
||||||
} else if domain := viper.GetString("letsencrypt.domain"); domain != "" {
|
} else if domain := cfg.LetsEncrypt.Domain; domain != "" {
|
||||||
dir := storage.Path.LetsEncrypt()
|
dir := storage.Path.LetsEncrypt()
|
||||||
email := viper.GetString("letsencrypt.email")
|
email := cfg.LetsEncrypt.Email
|
||||||
lePort := viper.GetString("letsencrypt.port")
|
lePort := cfg.LetsEncrypt.Port
|
||||||
|
|
||||||
if viper.GetBool("letsencrypt.proxy") && lePort != "" && (port != "80" || !redirect) {
|
if cfg.LetsEncrypt.Proxy && lePort != "" && (port != "80" || !redirect) {
|
||||||
log.Println("[HTTP] Listening on port 80 (Let's Encrypt Proxy))")
|
log.Println("[HTTP] Listening on port 80 (Let's Encrypt Proxy))")
|
||||||
go http.ListenAndServe(net.JoinHostPort(addr, "80"), http.HandlerFunc(letsEncryptProxy))
|
go http.ListenAndServe(net.JoinHostPort(addr, "80"), http.HandlerFunc(d.letsEncryptProxy))
|
||||||
}
|
}
|
||||||
|
|
||||||
le, err := letsencrypt.Run(dir, domain, email, ":"+lePort)
|
le, err := letsencrypt.Run(dir, domain, email, ":"+lePort)
|
||||||
@ -150,7 +173,7 @@ func (d *Dispatch) startHTTP() {
|
|||||||
log.Fatal("Could not locate SSL certificate or private key")
|
log.Fatal("Could not locate SSL certificate or private key")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if viper.GetBool("dev") {
|
if cfg.Dev {
|
||||||
// The node dev server will proxy index page requests and
|
// The node dev server will proxy index page requests and
|
||||||
// websocket connections to this port
|
// websocket connections to this port
|
||||||
port = "1337"
|
port = "1337"
|
||||||
@ -174,10 +197,9 @@ func (d *Dispatch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state := d.handleAuth(w, r, true, true)
|
state := d.handleAuth(w, r, true, true)
|
||||||
data := getIndexData(r, referer.EscapedPath(), state)
|
data := d.getIndexData(r, referer.EscapedPath(), state)
|
||||||
|
|
||||||
writeJSON(w, r, data)
|
writeJSON(w, r, data)
|
||||||
|
|
||||||
} else if strings.HasPrefix(r.URL.Path, "/ws") {
|
} else if strings.HasPrefix(r.URL.Path, "/ws") {
|
||||||
if !websocket.IsWebSocketUpgrade(r) {
|
if !websocket.IsWebSocketUpgrade(r) {
|
||||||
fail(w, http.StatusBadRequest)
|
fail(w, http.StatusBadRequest)
|
||||||
@ -207,10 +229,10 @@ func (d *Dispatch) upgradeWS(w http.ResponseWriter, r *http.Request, state *Stat
|
|||||||
newWSHandler(conn, state, r).run()
|
newWSHandler(conn, state, r).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHTTPSRedirect(portHTTPS string) http.HandlerFunc {
|
func (d *Dispatch) createHTTPSRedirect(portHTTPS string) http.HandlerFunc {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge") {
|
if strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge") {
|
||||||
letsEncryptProxy(w, r)
|
d.letsEncryptProxy(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +252,7 @@ func createHTTPSRedirect(portHTTPS string) http.HandlerFunc {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func letsEncryptProxy(w http.ResponseWriter, r *http.Request) {
|
func (d *Dispatch) letsEncryptProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
host, _, err := net.SplitHostPort(r.Host)
|
host, _, err := net.SplitHostPort(r.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
host = r.Host
|
host = r.Host
|
||||||
@ -238,7 +260,7 @@ func letsEncryptProxy(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
upstream := &url.URL{
|
upstream := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Host: net.JoinHostPort(host, viper.GetString("letsencrypt.port")),
|
Host: net.JoinHostPort(host, d.Config().LetsEncrypt.Port),
|
||||||
}
|
}
|
||||||
|
|
||||||
httputil.NewSingleHostReverseProxy(upstream).ServeHTTP(w, r)
|
httputil.NewSingleHostReverseProxy(upstream).ServeHTTP(w, r)
|
||||||
|
@ -2,22 +2,19 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func certExists() bool {
|
func (d *Dispatch) certExists() bool {
|
||||||
cert := viper.GetString("https.cert")
|
cfg := d.Config().HTTPS
|
||||||
key := viper.GetString("https.key")
|
|
||||||
|
|
||||||
if cert == "" || key == "" {
|
if cfg.Cert == "" || cfg.Key == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(cert); err != nil {
|
if _, err := os.Stat(cfg.Cert); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(key); err != nil {
|
if _, err := os.Stat(cfg.Key); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user