From 29d80366a681e5fa4a306dd540f762d484f2b7c9 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Tue, 12 Apr 2016 23:00:09 +1000 Subject: [PATCH] Use docopt for command-line processing and new YAML configuration format --- .gitignore | 1 + README.md | 12 ++++--- ergonomadic.conf | 15 -------- ergonomadic.go | 92 +++++++++++++++++++----------------------------- ergonomadic.yaml | 34 ++++++++++++++++++ irc/config.go | 26 ++++++++------ 6 files changed, 94 insertions(+), 86 deletions(-) delete mode 100644 ergonomadic.conf create mode 100644 ergonomadic.yaml diff --git a/.gitignore b/.gitignore index e69de29b..b1bdee32 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/ircd.* diff --git a/README.md b/README.md index a1ff1e51..be127e3a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Discussion at: * follows the RFCs where possible * UTF-8 nick and channel names -* [gcfg](https://github.com/go-gcfg/gcfg/tree/v1) gitconfig-style configuration +* [yaml](http://yaml.org/) configuration * server password (PASS command) * channels with most standard modes * IRC operators (OPER command) @@ -39,22 +39,24 @@ and channel sync issues created during netsplits. ```sh go get go install -ergonomadic initdb -conf ergonomadic.conf +cp ergonomadic.yaml ircd.yaml +vim ircd.yaml # modify the config file to your liking +ergonomadic initdb ``` # Configuration -See the example [`ergonomadic.conf`](ergonomadic.conf). Passwords are base64-encoded bcrypted byte +See the example [`ergonomadic.yaml`](ergonomadic.yaml). Passwords are base64-encoded bcrypted byte strings. You can generate them with the `genpasswd` subcommand. ```sh -ergonomadic genpasswd 'hunter2!' +ergonomadic genpasswd ``` # Running the server ```sh -ergonomadic run -conf ergonomadic.conf +ergonomadic run ``` # Credits diff --git a/ergonomadic.conf b/ergonomadic.conf deleted file mode 100644 index 7225b98b..00000000 --- a/ergonomadic.conf +++ /dev/null @@ -1,15 +0,0 @@ -[server] -name = "irc.example.com" ; required, usually a hostname -database = "ergonomadic.db" ; path relative to this file -listen = "localhost:6667" ; see `net.Listen` for examples -listen = "[::1]:6667" ; multiple `listen`s are allowed. -wslisten = ":8080" ; websocket listen -log = "debug" ; error, warn, info, debug -motd = "motd.txt" ; path relative to this file -password = "JDJhJDA0JHJzVFFlNXdOUXNhLmtkSGRUQVVEVHVYWXRKUmdNQ3FKVTRrczRSMTlSWGRPZHRSMVRzQmtt" ; 'test' - -[operator "root"] -password = "JDJhJDA0JEhkcm10UlNFRkRXb25iOHZuSDVLZXVBWlpyY0xyNkQ4dlBVc1VMWVk1LlFjWFpQbGxZNUtl" ; 'toor' - -[theater "#ghostbusters"] -password = "JDJhJDA0JG0yY1h4cTRFUHhkcjIzN2p1M2Nvb2VEYjAzSHh4eTB3YkZ0VFRLV1ZPVXdqeFBSRUtmRlBT" ; 'venkman' diff --git a/ergonomadic.go b/ergonomadic.go index 89da1f42..203650fe 100644 --- a/ergonomadic.go +++ b/ergonomadic.go @@ -1,81 +1,63 @@ package main import ( - "flag" "fmt" - "github.com/edmund-huber/ergonomadic/irc" "log" - "os" - "path/filepath" + "syscall" + + "github.com/docopt/docopt-go" + "github.com/edmund-huber/ergonomadic/irc" + "golang.org/x/crypto/ssh/terminal" ) -func usage() { - fmt.Fprintln(os.Stderr, "ergonomadic [options]") - fmt.Fprintln(os.Stderr, " run -conf -- run server") - fmt.Fprintln(os.Stderr, " initdb -conf -- initialize database") - fmt.Fprintln(os.Stderr, " upgrade -conf -- upgrade database") - fmt.Fprintln(os.Stderr, " genpasswd -- bcrypt a password") - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, "software version:", irc.SEM_VER) - flag.PrintDefaults() -} - -func loadConfig(conf string) *irc.Config { - config, err := irc.LoadConfig(conf) - if err != nil { - log.Fatalln("error loading config:", err) - } - - err = os.Chdir(filepath.Dir(conf)) - if err != nil { - log.Fatalln("chdir error:", err) - } - return config -} - -func genPasswd() { -} - func main() { - var conf string - flag.Usage = usage + version := irc.SEM_VER + usage := `ergonomadic. +Usage: + ergonomadic initdb [--conf ] + ergonomadic upgradedb [--conf ] + ergonomadic genpasswd [--conf ] + ergonomadic run [--conf ] + ergonomadic -h | --help + ergonomadic --version +Options: + --conf Configuration file to use [default: ircd.yaml]. + -h --help Show this screen. + --version Show version.` - runFlags := flag.NewFlagSet("run", flag.ExitOnError) - runFlags.Usage = usage - runFlags.StringVar(&conf, "conf", "ergonomadic.conf", "ergonomadic config file") + arguments, _ := docopt.Parse(usage, nil, true, version, false) - flag.Parse() + // load config now because it's the same process for all + configfile := arguments["--conf"].(string) + config, err := irc.LoadConfig(configfile) + if err != nil { + log.Fatal("Config file did not load successfully:", err.Error()) + } - switch flag.Arg(0) { - case "genpasswd": - encoded, err := irc.GenerateEncodedPassword(flag.Arg(1)) + if arguments["genpasswd"].(bool) { + fmt.Print("Enter Password: ") + bytePassword, err := terminal.ReadPassword(int(syscall.Stdin)) + if err != nil { + log.Fatal("Error reading password:", err.Error()) + } + password := string(bytePassword) + encoded, err := irc.GenerateEncodedPassword(password) if err != nil { log.Fatalln("encoding error:", err) } + fmt.Print("\n") fmt.Println(encoded) - - case "initdb": - runFlags.Parse(flag.Args()[1:]) - config := loadConfig(conf) + } else if arguments["initdb"].(bool) { irc.InitDB(config.Server.Database) log.Println("database initialized: ", config.Server.Database) - - case "upgradedb": - runFlags.Parse(flag.Args()[1:]) - config := loadConfig(conf) + } else if arguments["upgradedb"].(bool) { irc.UpgradeDB(config.Server.Database) log.Println("database upgraded: ", config.Server.Database) - - case "run": - runFlags.Parse(flag.Args()[1:]) - config := loadConfig(conf) + } else if arguments["run"].(bool) { irc.Log.SetLevel(config.Server.Log) server := irc.NewServer(config) log.Println(irc.SEM_VER, "running") defer log.Println(irc.SEM_VER, "exiting") server.Run() - - default: - usage() } } diff --git a/ergonomadic.yaml b/ergonomadic.yaml new file mode 100644 index 00000000..0b5f52de --- /dev/null +++ b/ergonomadic.yaml @@ -0,0 +1,34 @@ +# ergonomadic IRCd config +server: + # server name + name: ergonomadic.test + + # database filename (sqlite db) + database: ircd.db + + # addresses to listen on + listen: + - ":6667" + - "127.0.0.1:6668" + - "[::1]:6668" + + # websocket listening port + wslisten: ":8080" + + # password to login to the server + # generated using "ergonomadic genpasswd" + #password: "" + + # log level, one of error, warn, info, debug + log: debug + + # motd filename + motd: ircd.motd + +# ircd operators +operator: + # operator named 'dan' + dan: + # password to login with /OPER command + # generated using "ergonomadic genpasswd" + password: JDJhJDA0JE1vZmwxZC9YTXBhZ3RWT2xBbkNwZnV3R2N6VFUwQUI0RUJRVXRBRHliZVVoa0VYMnlIaGsu diff --git a/irc/config.go b/irc/config.go index 14b084ec..d748e6f7 100644 --- a/irc/config.go +++ b/irc/config.go @@ -1,9 +1,11 @@ package irc import ( - "gopkg.in/gcfg.v1" "errors" + "io/ioutil" "log" + + "gopkg.in/yaml.v2" ) type PassConfig struct { @@ -55,22 +57,24 @@ func (conf *Config) Theaters() map[Name][]byte { } func LoadConfig(filename string) (config *Config, err error) { - config = &Config{} - err = gcfg.ReadFileInto(config, filename) + data, err := ioutil.ReadFile(filename) if err != nil { - return + return nil, err } + + err = yaml.Unmarshal(data, &config) + if err != nil { + return nil, err + } + if config.Server.Name == "" { - err = errors.New("server.name missing") - return + return nil, errors.New("Server name missing") } if config.Server.Database == "" { - err = errors.New("server.database missing") - return + return nil, errors.New("Server database missing") } if len(config.Server.Listen) == 0 { - err = errors.New("server.listen missing") - return + return nil, errors.New("Server listening addresses missing") } - return + return config, nil }