Add CLI flags for token, config, and log (#245)
This commit is contained in:
parent
4cb58e0edf
commit
c9b4e114e0
4 changed files with 60 additions and 113 deletions
12
README.md
12
README.md
|
|
@ -65,17 +65,17 @@ sudo mv ./discordo /usr/local/bin
|
|||
|
||||
1. Run the `discordo` executable with no arguments.
|
||||
|
||||
2. A login view will be displayed on first start-up. You can choose to login using either your email and password or token; the views can be switched using `Ctrl+Space` keybinding.
|
||||
> If you are logging in using an authentication token, provide the `token` command-line flag to the executable (eg: `--token "OTI2MDU5NTQxNDE2Nzc5ODA2.Yc2KKA.2iZ-5JxgxG-9Ub8GHzBSn-NJjNg"`).
|
||||
|
||||
3. Enter your credentials and click on the "Login" button to continue.
|
||||
2. Enter your email and password and click on the "Login" button to continue.
|
||||
|
||||
- If you are logging in with a bot account, prefix the token with `Bot ` (eg: `Bot OTI2MDU5NTQxNDE2Nzc5ODA2.Yc2KKA.2iZ-5JxgxG-9Ub8GHzBSn-NJjNg`).
|
||||
|
||||
- Most of the Discord third-party clients store the token in a configuration file unencrypted. Discordo securely stores the token in the default OS-specific keyring.
|
||||
- Most of the Discord third-party clients store the token in a configuration file unencrypted. Discordo securely stores the token in the default OS-specific keyring.
|
||||
|
||||
### Configuration
|
||||
|
||||
A default configuration file is created on first start-up at `$HOME/.config/discordo/config.yml` on Unix, `$HOME/Library/Application Support/discordo/config.yml` on Darwin, and `%AppData%/discordo/config.yml` on Windows.
|
||||
A default configuration file is created on first start-up at `$HOME/.config/discordo.yml` on Unix, `$HOME/Library/Application Support/discordo.yml` on Darwin, and `%AppData%/discordo.yml` on Windows. The configuration file path can be customized using the `config` command-line flag (eg: `--config ~/myconfigs/discordo.yml`).
|
||||
|
||||
Similarly, a log file is created on first start-up at `$HOME/.cache/discordo.log` on Unix, `$HOME/Library/Caches/discordo.log` on Darwin, and `%LocalAppData%/discordo.yml` on Windows. The log file path can be customized using the `log` command-line flag.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ func New() *Config {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *Config) Load() error {
|
||||
func (cfg *Config) Load(path string) error {
|
||||
// Open the existing configuration file with read-only flag.
|
||||
f, err := os.OpenFile(cfg.configPath(), os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -101,10 +101,14 @@ func (cfg *Config) Load() error {
|
|||
return yaml.NewDecoder(f).Decode(&cfg)
|
||||
}
|
||||
|
||||
func (cfg *Config) configPath() string {
|
||||
// DefaultConfigPath returns the default configuration file path.
|
||||
func DefaultConfigPath() string {
|
||||
path, _ := os.UserConfigDir()
|
||||
path = filepath.Join(path, Name)
|
||||
// Create the configuration directory if it does not exist already.
|
||||
_ = os.MkdirAll(path, os.ModePerm)
|
||||
return filepath.Join(path, "config.yml")
|
||||
return filepath.Join(path, Name+".yml")
|
||||
}
|
||||
|
||||
// DefaultLogPath returns the default log file path.
|
||||
func DefaultLogPath() string {
|
||||
path, _ := os.UserCacheDir()
|
||||
return filepath.Join(path, Name+".log")
|
||||
}
|
||||
|
|
|
|||
59
main.go
59
main.go
|
|
@ -1,10 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/ayntgl/discordo/config"
|
||||
|
|
@ -15,27 +15,13 @@ import (
|
|||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
var (
|
||||
flagToken string
|
||||
flagConfig string
|
||||
flagLog string
|
||||
)
|
||||
|
||||
func init() {
|
||||
path, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
path = filepath.Join(path, config.Name)
|
||||
err = os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
path = filepath.Join(path, "out.log")
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.SetOutput(f)
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
tview.Borders.TopLeftFocus = tview.Borders.TopLeft
|
||||
tview.Borders.TopRightFocus = tview.Borders.TopRight
|
||||
tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
|
||||
|
|
@ -55,18 +41,41 @@ func init() {
|
|||
Browser: config.Name,
|
||||
Device: "",
|
||||
}
|
||||
|
||||
flag.StringVar(&flagToken, "token", "", "The authentication token.")
|
||||
flag.StringVar(&flagConfig, "config", config.DefaultConfigPath(), "The path to the configuration file.")
|
||||
flag.StringVar(&flagLog, "log", config.DefaultLogPath(), "The path to the log file.")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if flagLog != "" {
|
||||
// Set the standard logger output to the provided log file.
|
||||
f, err := os.OpenFile(flagLog, os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.SetOutput(f)
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
}
|
||||
|
||||
cfg := config.New()
|
||||
err := cfg.Load()
|
||||
err := cfg.Load(flagConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
token, err := keyring.Get(config.Name, "token")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
var token string
|
||||
if flagToken != "" {
|
||||
token = flagToken
|
||||
go keyring.Set(config.Name, "token", token)
|
||||
} else {
|
||||
token, err = keyring.Get(config.Name, "token")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
c := ui.NewCore(cfg)
|
||||
|
|
|
|||
|
|
@ -6,56 +6,17 @@ import (
|
|||
|
||||
"github.com/ayntgl/discordo/config"
|
||||
"github.com/diamondburned/arikawa/v3/api"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
const (
|
||||
emailViewPageName = "email"
|
||||
tokenViewPageName = "token"
|
||||
)
|
||||
|
||||
func NewLoginView(c *Core) *tview.Pages {
|
||||
v := tview.NewPages()
|
||||
|
||||
v.AddPage(emailViewPageName, newEmailView(c), true, true)
|
||||
v.AddPage(tokenViewPageName, newTokenView(c), true, true)
|
||||
// Since the recommended method to login is using the email and password, it is displayed on the screen first.
|
||||
v.SwitchToPage(emailViewPageName)
|
||||
|
||||
v.SetTitle("Login")
|
||||
v.SetTitleAlign(tview.AlignLeft)
|
||||
v.SetBorder(true)
|
||||
v.SetBorderPadding(0, 0, 1, 1)
|
||||
v.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
if event.Key() == tcell.KeyCtrlSpace {
|
||||
name, _ := v.GetFrontPage()
|
||||
|
||||
switch name {
|
||||
case emailViewPageName:
|
||||
name = tokenViewPageName
|
||||
case tokenViewPageName:
|
||||
name = emailViewPageName
|
||||
}
|
||||
|
||||
v.SwitchToPage(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
})
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
type EmailView struct {
|
||||
type LoginView struct {
|
||||
*tview.Form
|
||||
core *Core
|
||||
}
|
||||
|
||||
func newEmailView(c *Core) *EmailView {
|
||||
v := &EmailView{
|
||||
func NewLoginView(c *Core) *LoginView {
|
||||
v := &LoginView{
|
||||
Form: tview.NewForm(),
|
||||
core: c,
|
||||
}
|
||||
|
|
@ -65,10 +26,15 @@ func newEmailView(c *Core) *EmailView {
|
|||
v.AddPasswordField("Code (optional)", "", 0, 0, nil)
|
||||
v.AddButton("Login", v.onLoginButtonSelected)
|
||||
|
||||
v.SetTitle("Login")
|
||||
v.SetTitleAlign(tview.AlignLeft)
|
||||
v.SetBorder(true)
|
||||
v.SetBorderPadding(1, 1, 1, 1)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *EmailView) onLoginButtonSelected() {
|
||||
func (v *LoginView) onLoginButtonSelected() {
|
||||
email := v.GetFormItem(0).(*tview.InputField).GetText()
|
||||
password := v.GetFormItem(1).(*tview.InputField).GetText()
|
||||
if email == "" || password == "" {
|
||||
|
|
@ -105,35 +71,3 @@ func (v *EmailView) onLoginButtonSelected() {
|
|||
v.core.Draw()
|
||||
go keyring.Set(config.Name, "token", l.Token)
|
||||
}
|
||||
|
||||
type TokenView struct {
|
||||
*tview.Form
|
||||
core *Core
|
||||
}
|
||||
|
||||
func newTokenView(c *Core) *TokenView {
|
||||
v := &TokenView{
|
||||
Form: tview.NewForm(),
|
||||
core: c,
|
||||
}
|
||||
|
||||
v.AddPasswordField("Token", "", 0, 0, nil)
|
||||
v.AddButton("Login", v.onLoginButtonSelected)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *TokenView) onLoginButtonSelected() {
|
||||
token := v.GetFormItem(0).(*tview.InputField).GetText()
|
||||
if token == "" {
|
||||
return
|
||||
}
|
||||
|
||||
err := v.core.Run(token)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
v.core.Draw()
|
||||
go keyring.Set(config.Name, "token", token)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue