Changeset 691 in code


Ignore:
Timestamp:
Nov 15, 2021, 11:38:04 PM (4 years ago)
Author:
contact
Message:

Allow most config options to be reloaded

Closes: https://todo.sr.ht/~emersion/soju/42

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/cmd/soju/main.go

    r687 r691  
    3838}
    3939
    40 func loadMOTD(srv *soju.Server, filename string) error {
    41         if filename == "" {
    42                 return nil
    43         }
    44 
    45         b, err := ioutil.ReadFile(filename)
    46         if err != nil {
    47                 return err
    48         }
    49         srv.SetMOTD(strings.TrimSuffix(string(b), "\n"))
    50         return nil
    51 }
    52 
    5340func bumpOpenedFileLimit() error {
    5441        var rlimit syscall.Rlimit
     
    6350}
    6451
     52var (
     53        configPath string
     54        debug      bool
     55
     56        tlsCert atomic.Value // *tls.Certificate
     57)
     58
     59func loadConfig() (*config.Server, *soju.Config, error) {
     60        var raw *config.Server
     61        if configPath != "" {
     62                var err error
     63                raw, err = config.Load(configPath)
     64                if err != nil {
     65                        return nil, nil, fmt.Errorf("failed to load config file: %v", err)
     66                }
     67        } else {
     68                raw = config.Defaults()
     69        }
     70
     71        var motd string
     72        if raw.MOTDPath != "" {
     73                b, err := ioutil.ReadFile(raw.MOTDPath)
     74                if err != nil {
     75                        return nil, nil, fmt.Errorf("failed to load MOTD: %v", err)
     76                }
     77                motd = strings.TrimSuffix(string(b), "\n")
     78        }
     79
     80        if raw.TLS != nil {
     81                cert, err := tls.LoadX509KeyPair(raw.TLS.CertPath, raw.TLS.KeyPath)
     82                if err != nil {
     83                        return nil, nil, fmt.Errorf("failed to load TLS certificate and key: %v", err)
     84                }
     85                tlsCert.Store(&cert)
     86        }
     87
     88        cfg := &soju.Config{
     89                Hostname:        raw.Hostname,
     90                Title:           raw.Title,
     91                LogPath:         raw.LogPath,
     92                HTTPOrigins:     raw.HTTPOrigins,
     93                AcceptProxyIPs:  raw.AcceptProxyIPs,
     94                MaxUserNetworks: raw.MaxUserNetworks,
     95                Debug:           debug,
     96                MOTD:            motd,
     97        }
     98        return raw, cfg, nil
     99}
     100
    65101func main() {
    66102        var listen []string
    67         var configPath string
    68         var debug bool
    69103        flag.Var((*stringSliceFlag)(&listen), "listen", "listening address")
    70104        flag.StringVar(&configPath, "config", "", "path to configuration file")
     
    72106        flag.Parse()
    73107
    74         var cfg *config.Server
    75         if configPath != "" {
    76                 var err error
    77                 cfg, err = config.Load(configPath)
    78                 if err != nil {
    79                         log.Fatalf("failed to load config file: %v", err)
    80                 }
    81         } else {
    82                 cfg = config.Defaults()
     108        cfg, serverCfg, err := loadConfig()
     109        if err != nil {
     110                log.Fatal(err)
    83111        }
    84112
     
    98126
    99127        var tlsCfg *tls.Config
    100         var tlsCert atomic.Value
    101128        if cfg.TLS != nil {
    102                 cert, err := tls.LoadX509KeyPair(cfg.TLS.CertPath, cfg.TLS.KeyPath)
    103                 if err != nil {
    104                         log.Fatalf("failed to load TLS certificate and key: %v", err)
    105                 }
    106                 tlsCert.Store(&cert)
    107 
    108129                tlsCfg = &tls.Config{
    109130                        GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
     
    114135
    115136        srv := soju.NewServer(db)
    116         srv.Hostname = cfg.Hostname
    117         srv.Title = cfg.Title
    118         srv.LogPath = cfg.LogPath
    119         srv.HTTPOrigins = cfg.HTTPOrigins
    120         srv.AcceptProxyIPs = cfg.AcceptProxyIPs
    121         srv.MaxUserNetworks = cfg.MaxUserNetworks
    122         srv.Debug = debug
    123 
    124         if err := loadMOTD(srv, cfg.MOTDPath); err != nil {
    125                 log.Fatalf("failed to load MOTD: %v", err)
    126         }
     137        srv.SetConfig(serverCfg)
    127138
    128139        for _, listen := range cfg.Listen {
     
    259270                switch sig {
    260271                case syscall.SIGHUP:
    261                         log.Print("reloading TLS certificate and MOTD")
    262                         if cfg.TLS != nil {
    263                                 cert, err := tls.LoadX509KeyPair(cfg.TLS.CertPath, cfg.TLS.KeyPath)
    264                                 if err != nil {
    265                                         log.Printf("failed to reload TLS certificate and key: %v", err)
    266                                         break
    267                                 }
    268                                 tlsCert.Store(&cert)
    269                         }
    270                         if err := loadMOTD(srv, cfg.MOTDPath); err != nil {
    271                                 log.Printf("failed to reload MOTD: %v", err)
     272                        log.Print("reloading configuration")
     273                        _, serverCfg, err := loadConfig()
     274                        if err != nil {
     275                                log.Printf("failed to reloading configuration: %v", err)
     276                        } else {
     277                                srv.SetConfig(serverCfg)
    272278                        }
    273279                case syscall.SIGINT, syscall.SIGTERM:
     
    287293                                return proxyproto.IGNORE, nil
    288294                        }
    289                         if srv.AcceptProxyIPs.Contains(tcpAddr.IP) {
     295                        if srv.Config().AcceptProxyIPs.Contains(tcpAddr.IP) {
    290296                                return proxyproto.USE, nil
    291297                        }
  • trunk/conn.go

    r594 r691  
    196196                        }
    197197
    198                         if c.srv.Debug {
     198                        if c.srv.Config().Debug {
    199199                                c.logger.Printf("sent: %v", msg)
    200200                        }
     
    249249        }
    250250
    251         if c.srv.Debug {
     251        if c.srv.Config().Debug {
    252252                c.logger.Printf("received: %v", msg)
    253253        }
  • trunk/doc/soju.1.scd

    r662 r691  
    4545be done by adding a "@<client>" suffix to the username.
    4646
    47 soju will reload the TLS certificate/key and the MOTD file when it receives the
    48 HUP signal.
     47soju will reload the configuration file, the TLS certificate/key and the MOTD
     48file when it receives the HUP signal. The configuration options _listen_, _db_
     49and _log_ cannot be reloaded.
    4950
    5051Administrators can broadcast a message to all bouncer users via _/notice
  • trunk/downstream.go

    r690 r691  
    291291                dc.supportedCaps[k] = v
    292292        }
    293         if srv.LogPath != "" {
     293        // TODO: this is racy, we should only enable chathistory after
     294        // authentication and then check that user.msgStore implements
     295        // chatHistoryMessageStore
     296        if srv.Config().LogPath != "" {
    294297                dc.supportedCaps["draft/chathistory"] = ""
    295298        }
     
    9971000        }
    9981001
    999         if dc.srv.LogPath != "" && dc.network != nil {
     1002        if _, ok := dc.user.msgStore.(chatHistoryMessageStore); ok && dc.network != nil {
    10001003                dc.setSupportedCap("draft/event-playback", "")
    10011004        } else {
     
    11761179                isupport = append(isupport, fmt.Sprintf("BOUNCER_NETID=%v", dc.network.ID))
    11771180        }
    1178         if dc.network == nil && dc.srv.Title != "" {
    1179                 isupport = append(isupport, "NETWORK="+encodeISUPPORT(dc.srv.Title))
     1181        if title := dc.srv.Config().Title; dc.network == nil && title != "" {
     1182                isupport = append(isupport, "NETWORK="+encodeISUPPORT(title))
    11801183        }
    11811184        if dc.network == nil && dc.caps["soju.im/bouncer-networks"] {
     
    12051208                Prefix:  dc.srv.prefix(),
    12061209                Command: irc.RPL_YOURHOST,
    1207                 Params:  []string{dc.nick, "Your host is " + dc.srv.Hostname},
     1210                Params:  []string{dc.nick, "Your host is " + dc.srv.Config().Hostname},
    12081211        })
    12091212        dc.SendMessage(&irc.Message{
    12101213                Prefix:  dc.srv.prefix(),
    12111214                Command: irc.RPL_MYINFO,
    1212                 Params:  []string{dc.nick, dc.srv.Hostname, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
     1215                Params:  []string{dc.nick, dc.srv.Config().Hostname, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
    12131216        })
    12141217        for _, msg := range generateIsupport(dc.srv.prefix(), dc.nick, isupport) {
     
    12301233        }
    12311234
    1232         if motd := dc.user.srv.MOTD(); motd != "" && dc.network == nil {
     1235        if motd := dc.user.srv.Config().MOTD; motd != "" && dc.network == nil {
    12331236                for _, msg := range generateMOTD(dc.srv.prefix(), dc.nick, motd) {
    12341237                        dc.SendMessage(msg)
     
    14211424                        destination = msg.Params[1]
    14221425                }
    1423                 if destination != "" && destination != dc.srv.Hostname {
     1426                hostname := dc.srv.Config().Hostname
     1427                if destination != "" && destination != hostname {
    14241428                        return ircError{&irc.Message{
    14251429                                Command: irc.ERR_NOSUCHSERVER,
     
    14301434                        Prefix:  dc.srv.prefix(),
    14311435                        Command: "PONG",
    1432                         Params:  []string{dc.srv.Hostname, source},
     1436                        Params:  []string{hostname, source},
    14331437                })
    14341438                return nil
     
    19471951                                Username: dc.user.Username,
    19481952                                Hostname: dc.hostname,
    1949                                 Server:   dc.srv.Hostname,
     1953                                Server:   dc.srv.Config().Hostname,
    19501954                                Nickname: dc.nick,
    19511955                                Flags:    flags,
     
    19661970                                Username: servicePrefix.User,
    19671971                                Hostname: servicePrefix.Host,
    1968                                 Server:   dc.srv.Hostname,
     1972                                Server:   dc.srv.Config().Hostname,
    19691973                                Nickname: serviceNick,
    19701974                                Flags:    "H*",
     
    20262030                                Prefix:  dc.srv.prefix(),
    20272031                                Command: irc.RPL_WHOISSERVER,
    2028                                 Params:  []string{dc.nick, dc.nick, dc.srv.Hostname, "soju"},
     2032                                Params:  []string{dc.nick, dc.nick, dc.srv.Config().Hostname, "soju"},
    20292033                        })
    20302034                        if dc.user.Admin {
     
    20562060                                Prefix:  dc.srv.prefix(),
    20572061                                Command: irc.RPL_WHOISSERVER,
    2058                                 Params:  []string{dc.nick, serviceNick, dc.srv.Hostname, "soju"},
     2062                                Params:  []string{dc.nick, serviceNick, dc.srv.Config().Hostname, "soju"},
    20592063                        })
    20602064                        dc.SendMessage(&irc.Message{
     
    21052109
    21062110                for _, name := range strings.Split(targetsStr, ",") {
    2107                         if name == "$"+dc.srv.Hostname || (name == "$*" && dc.network == nil) {
     2111                        if name == "$"+dc.srv.Config().Hostname || (name == "$*" && dc.network == nil) {
    21082112                                // "$" means a server mask follows. If it's the bouncer's
    21092113                                // hostname, broadcast the message to all bouncer users.
  • trunk/server.go

    r689 r691  
    5454}
    5555
    56 type Server struct {
     56type Config struct {
    5757        Hostname        string
    5858        Title           string
    59         Logger          Logger
    6059        LogPath         string
    6160        Debug           bool
     
    6362        AcceptProxyIPs  config.IPSet
    6463        MaxUserNetworks int
    65         Identd          *Identd // can be nil
    66 
     64        MOTD            string
     65}
     66
     67type Server struct {
     68        Logger Logger
     69        Identd *Identd // can be nil
     70
     71        config    atomic.Value // *Config
    6772        db        Database
    6873        stopWG    sync.WaitGroup
     
    7277        listeners map[net.Listener]struct{}
    7378        users     map[string]*user
    74 
    75         motd atomic.Value // string
    7679}
    7780
    7881func NewServer(db Database) *Server {
    7982        srv := &Server{
    80                 Logger:          log.New(log.Writer(), "", log.LstdFlags),
    81                 MaxUserNetworks: -1,
    82                 db:              db,
    83                 listeners:       make(map[net.Listener]struct{}),
    84                 users:           make(map[string]*user),
    85         }
    86         srv.motd.Store("")
     83                Logger:    log.New(log.Writer(), "", log.LstdFlags),
     84                db:        db,
     85                listeners: make(map[net.Listener]struct{}),
     86                users:     make(map[string]*user),
     87        }
     88        srv.config.Store(&Config{Hostname: "localhost", MaxUserNetworks: -1})
    8789        return srv
    8890}
    8991
    9092func (s *Server) prefix() *irc.Prefix {
    91         return &irc.Prefix{Name: s.Hostname}
     93        return &irc.Prefix{Name: s.Config().Hostname}
     94}
     95
     96func (s *Server) Config() *Config {
     97        return s.config.Load().(*Config)
     98}
     99
     100func (s *Server) SetConfig(cfg *Config) {
     101        s.config.Store(cfg)
    92102}
    93103
     
    240250        conn, err := websocket.Accept(w, req, &websocket.AcceptOptions{
    241251                Subprotocols:   []string{"text.ircv3.net"}, // non-compliant, fight me
    242                 OriginPatterns: s.HTTPOrigins,
     252                OriginPatterns: s.Config().HTTPOrigins,
    243253        })
    244254        if err != nil {
     
    250260        if host, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
    251261                if ip := net.ParseIP(host); ip != nil {
    252                         isProxy = s.AcceptProxyIPs.Contains(ip)
     262                        isProxy = s.Config().AcceptProxyIPs.Contains(ip)
    253263                }
    254264        }
     
    294304        return &stats
    295305}
    296 
    297 func (s *Server) SetMOTD(motd string) {
    298         s.motd.Store(motd)
    299 }
    300 
    301 func (s *Server) MOTD() string {
    302         return s.motd.Load().(string)
    303 }
  • trunk/service.go

    r680 r691  
    10511051                Prefix:  servicePrefix,
    10521052                Command: "NOTICE",
    1053                 Params:  []string{"$" + dc.srv.Hostname, text},
     1053                Params:  []string{"$" + dc.srv.Config().Hostname, text},
    10541054        }
    10551055        var err error
  • trunk/user.go

    r684 r691  
    416416
    417417        var msgStore messageStore
    418         if srv.LogPath != "" {
    419                 msgStore = newFSMessageStore(srv.LogPath, record.Username)
     418        if logPath := srv.Config().LogPath; logPath != "" {
     419                msgStore = newFSMessageStore(logPath, record.Username)
    420420        } else {
    421421                msgStore = newMemoryMessageStore()
     
    777777        }
    778778
    779         if u.srv.MaxUserNetworks >= 0 && len(u.networks) >= u.srv.MaxUserNetworks {
     779        if max := u.srv.Config().MaxUserNetworks; max >= 0 && len(u.networks) >= max {
    780780                return nil, fmt.Errorf("maximum number of networks reached")
    781781        }
Note: See TracChangeset for help on using the changeset viewer.