Skip to content

Commit

Permalink
Use spf13/viper for managing the configuration file (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
claudiodangelis authored Apr 1, 2023
1 parent 63dc102 commit 7499c16
Show file tree
Hide file tree
Showing 15 changed files with 553 additions and 358 deletions.
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ If you use [Scoop](https://scoop.sh/) for package management on Windows, you can
```
scoop install qrcp
```
### Chocolatey

If you use [Chocolatey](https://community.chocolatey.org/packages/qrcp) for package management on Windows, you can install qrcp with the following one-liner:

```
choco install qrcp
```

## MacOS

Expand Down Expand Up @@ -179,9 +186,39 @@ qrcp receive --output=/tmp/dir
```


## Options
## Configuration

`qrcp` works without any prior configuration, however, you can choose to configure to use specific values.

To configure `qrcp` you can create a configuration file inside `$XDG_CONFIG_HOME/qrcp`.

> Note: On Linux, the `$XDG_CONFIG_HOME` is `.config` under user home directory.
> So, for example, on Linux the configuration file will be `$HOME/.config/qrcp/config.yml`.
> Note: Starting from version 0.10.0, qrcp uses a YAML configuration file instead of the old JSON one. You can automatically migrate the legacy JSON format to the new YAML format by running `qrcp config migrate`.
| Key | Type | Notes |
|-------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `interface` | String | This value is automatically discovered during the first launch of `qrcp`, you can set it to override the default. You can use the `any` interface to bind the web server to `0.0.0.0`. |
| `port` | Integer | When this value is not set, `qrcp` will pick a random port at any launch. |
| `path` | String | When this value is not set, `qrcp` will add a random string at the end of URL. |
| `output` | String | Default directory to receive files to. If empty, the current working directory is used. |
| `fqdn` | String | When this value is set, `qrcp` will use it to replace the IP address in the generated URL. |
| `keepAlive` | Bool | Controls whether `qrcp` should quit after transferring the file. Defaults to `false`. |
| `secure` | Bool | Controls whether `qrcp` should use HTTPS instead of HTTP. Defaults to `false` |
| `tls-cert` | String | Path to the TLS certificate. It's only used when `secure: true`. |
| `tls-key` | String | Path to the TLS key. It's only used when `secure: true`. |


All the configuration parameters can be controlled via environment variables prefixed with `QRCP_`, for example:
- `$QRCP_INTERFACE`
- `$QRCP_PORT`
- `$QRCP_KEEPALIVE`
- _etc_

### Config Wizard

`qrcp` works without any prior configuration, however, you can choose to configure to use specific values. The `config` command launches a wizard that lets you configure parameters like interface, port, fully-qualified domain name and keep alive.
The `config` command launches a wizard that lets you configure parameters like interface, port, fully-qualified domain name and keep alive.

```sh
qrcp config
Expand All @@ -196,10 +233,10 @@ qrcp --list-all-interfaces config

### Configuration File

The default configuration file is stored in $XDG_CONFIG_HOME/qrcp/config.json, however, you can specify the location of the config file by passing the `--config` flag:
The default configuration file is stored in $XDG_CONFIG_HOME/qrcp/config.yml, however, you can specify the location of the config file by passing the `--config` flag:

```sh
qrcp --config /tmp/qrcp.json MyDocument.pdf
qrcp --config /tmp/qrcp.yml MyDocument.pdf
```

### Port
Expand Down
30 changes: 30 additions & 0 deletions application/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package application

type Flags struct {
Quiet bool
KeepAlive bool
ListAllInterfaces bool
Port int
Path string
Interface string
FQDN string
Zip bool
Config string
Browser bool
Secure bool
TlsCert string
TlsKey string
Output string
}

type App struct {
Flags Flags
Name string
}

func New() App {
return App{
Name: "qrcp",
Flags: Flags{},
}
}
19 changes: 18 additions & 1 deletion cmd/config.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package cmd

import (
"fmt"

"github.com/claudiodangelis/qrcp/config"
"github.com/spf13/cobra"
)

func configCmdFunc(command *cobra.Command, args []string) error {
return config.Wizard(configFlag, listallinterfacesFlag)
return config.Wizard(app)
}

var configCmd = &cobra.Command{
Expand All @@ -16,3 +18,18 @@ var configCmd = &cobra.Command{
Aliases: []string{"c", "cfg"},
RunE: configCmdFunc,
}

var migrateCmd = &cobra.Command{
Use: "migrate",
Short: "Migrate the legacy configuration file",
Long: "Migrate the legacy JSON configuration file to the new YAML format",
Run: func(cmd *cobra.Command, args []string) {
ok, err := config.Migrate(app)
if err != nil {
fmt.Println("error while migrating the legacy JSON configuration file:", err)
}
if ok {
fmt.Println("Legacy JSON configuration file has been successfully deleted")
}
},
}
49 changes: 19 additions & 30 deletions cmd/qrcp.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,38 @@
package cmd

import (
"github.com/claudiodangelis/qrcp/application"
"github.com/spf13/cobra"
)

var app application.App

func init() {
app = application.New()
rootCmd.AddCommand(sendCmd)
rootCmd.AddCommand(receiveCmd)
rootCmd.AddCommand(configCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(completionCmd)
configCmd.AddCommand(migrateCmd)
// Global command flags
rootCmd.PersistentFlags().BoolVarP(&quietFlag, "quiet", "q", false, "only print errors")
rootCmd.PersistentFlags().BoolVarP(&keepaliveFlag, "keep-alive", "k", false, "keep server alive after transferring")
rootCmd.PersistentFlags().BoolVarP(&listallinterfacesFlag, "list-all-interfaces", "l", false, "list all available interfaces when choosing the one to use")
rootCmd.PersistentFlags().IntVarP(&portFlag, "port", "p", 0, "port to use for the server")
rootCmd.PersistentFlags().StringVar(&pathFlag, "path", "", "path to use. Defaults to a random string")
rootCmd.PersistentFlags().StringVarP(&interfaceFlag, "interface", "i", "", "network interface to use for the server")
rootCmd.PersistentFlags().StringVarP(&fqdnFlag, "fqdn", "d", "", "fully-qualified domain name to use for the resulting URLs")
rootCmd.PersistentFlags().BoolVarP(&zipFlag, "zip", "z", false, "zip content before transferring")
rootCmd.PersistentFlags().StringVarP(&configFlag, "config", "c", "", "path to the config file, defaults to $XDG_CONFIG_HOME/qrcp/config.json")
rootCmd.PersistentFlags().BoolVarP(&browserFlag, "browser", "b", false, "display the QR code in a browser window")
rootCmd.PersistentFlags().BoolVarP(&secureFlag, "secure", "s", false, "use https connection")
rootCmd.PersistentFlags().StringVar(&tlscertFlag, "tls-cert", "", "path to TLS certificate to use with HTTPS")
rootCmd.PersistentFlags().StringVar(&tlskeyFlag, "tls-key", "", "path to TLS private key to use with HTTPS")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.Quiet, "quiet", "q", false, "only print errors")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.KeepAlive, "keep-alive", "k", false, "keep server alive after transferring")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.ListAllInterfaces, "list-all-interfaces", "l", false, "list all available interfaces when choosing the one to use")
rootCmd.PersistentFlags().IntVarP(&app.Flags.Port, "port", "p", 0, "port to use for the server")
rootCmd.PersistentFlags().StringVar(&app.Flags.Path, "path", "", "path to use. Defaults to a random string")
rootCmd.PersistentFlags().StringVarP(&app.Flags.Interface, "interface", "i", "", "network interface to use for the server")
rootCmd.PersistentFlags().StringVarP(&app.Flags.FQDN, "fqdn", "d", "", "fully-qualified domain name to use for the resulting URLs")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.Zip, "zip", "z", false, "zip content before transferring")
rootCmd.PersistentFlags().StringVarP(&app.Flags.Config, "config", "c", "", "path to the config file, defaults to $XDG_CONFIG_HOME/qrcp/config.json")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.Browser, "browser", "b", false, "display the QR code in a browser window")
rootCmd.PersistentFlags().BoolVarP(&app.Flags.Secure, "secure", "s", false, "use https connection")
rootCmd.PersistentFlags().StringVar(&app.Flags.TlsCert, "tls-cert", "", "path to TLS certificate to use with HTTPS")
rootCmd.PersistentFlags().StringVar(&app.Flags.TlsKey, "tls-key", "", "path to TLS private key to use with HTTPS")
// Receive command flags
receiveCmd.PersistentFlags().StringVarP(&outputFlag, "output", "o", "", "output directory for receiving files")
receiveCmd.PersistentFlags().StringVarP(&app.Flags.Output, "output", "o", "", "output directory for receiving files")
}

// Flags
var zipFlag bool
var portFlag int
var interfaceFlag string
var outputFlag string
var keepaliveFlag bool
var quietFlag bool
var fqdnFlag string
var pathFlag string
var listallinterfacesFlag bool
var configFlag string
var browserFlag bool
var secureFlag bool
var tlscertFlag string
var tlskeyFlag string

// The root command (`qrcp`) is like a shortcut of the `send` command
var rootCmd = &cobra.Command{
Use: "qrcp",
Expand Down
21 changes: 3 additions & 18 deletions cmd/receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,9 @@ import (
)

func receiveCmdFunc(command *cobra.Command, args []string) error {
log := logger.New(quietFlag)
log := logger.New(app.Flags.Quiet)
// Load configuration
configOptions := config.Options{
Interface: interfaceFlag,
Port: portFlag,
Path: pathFlag,
FQDN: fqdnFlag,
KeepAlive: keepaliveFlag,
ListAllInterfaces: listallinterfacesFlag,
Secure: secureFlag,
TLSCert: tlscertFlag,
TLSKey: tlskeyFlag,
Output: outputFlag,
}
cfg, err := config.New(configFlag, configOptions)
if err != nil {
return err
}
cfg := config.New(app)
// Create the server
srv, err := server.New(&cfg)
if err != nil {
Expand All @@ -44,7 +29,7 @@ func receiveCmdFunc(command *cobra.Command, args []string) error {
log.Print(srv.ReceiveURL)
// Renders the QR
qr.RenderString(srv.ReceiveURL)
if browserFlag {
if app.Flags.Browser {
srv.DisplayQR(srv.ReceiveURL)
}
if err := keyboard.Open(); err == nil {
Expand Down
20 changes: 4 additions & 16 deletions cmd/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,12 @@ import (
)

func sendCmdFunc(command *cobra.Command, args []string) error {
log := logger.New(quietFlag)
payload, err := payload.FromArgs(args, zipFlag)
log := logger.New(app.Flags.Quiet)
payload, err := payload.FromArgs(args, app.Flags.Zip)
if err != nil {
return err
}
// Load configuration
configOptions := config.Options{
Interface: interfaceFlag,
Port: portFlag,
Path: pathFlag,
FQDN: fqdnFlag,
KeepAlive: keepaliveFlag,
ListAllInterfaces: listallinterfacesFlag,
Secure: secureFlag,
TLSCert: tlscertFlag,
TLSKey: tlskeyFlag,
}
cfg, err := config.New(configFlag, configOptions)
cfg := config.New(app)
if err != nil {
return err
}
Expand All @@ -44,7 +32,7 @@ func sendCmdFunc(command *cobra.Command, args []string) error {
log.Print(`Scan the following URL with a QR reader to start the file transfer, press CTRL+C or "q" to exit:`)
log.Print(srv.SendURL)
qr.RenderString(srv.SendURL)
if browserFlag {
if app.Flags.Browser {
srv.DisplayQR(srv.SendURL)
}
if err := keyboard.Open(); err == nil {
Expand Down
Loading

0 comments on commit 7499c16

Please sign in to comment.