mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Add CLI main and TOML configuration
This commit is contained in:
76
cmd/podsync/main.go
Normal file
76
cmd/podsync/main.go
Normal file
@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/mxpv/podsync/pkg/config"
|
||||
)
|
||||
|
||||
type Opts struct {
|
||||
Config string `long:"config" short:"c" default:"config.toml"`
|
||||
Debug bool `long:"debug" short:"d"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetFormatter(&log.TextFormatter{})
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Parse args
|
||||
opts := Opts{}
|
||||
_, err := flags.Parse(&opts)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("failed to parse command line arguments")
|
||||
}
|
||||
|
||||
if opts.Debug {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
|
||||
// Load TOML file
|
||||
log.Debugf("loading configuration %q", opts.Config)
|
||||
cfg, err := config.LoadConfig(opts.Config)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("failed to load configuration file")
|
||||
}
|
||||
|
||||
// Create web server
|
||||
if cfg.Port == 0 {
|
||||
log.Debug("using default port 8080")
|
||||
cfg.Port = 8080
|
||||
}
|
||||
|
||||
srv := http.Server{
|
||||
Addr: fmt.Sprintf(":%d", cfg.Port),
|
||||
}
|
||||
|
||||
// Run listener
|
||||
go func() {
|
||||
log.Infof("running listener at %s", srv.Addr)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
log.WithError(err).Error("failed to listen")
|
||||
}
|
||||
}()
|
||||
|
||||
<-stop
|
||||
|
||||
log.Info("shutting down")
|
||||
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.WithError(err).Error("server shutdown failed")
|
||||
}
|
||||
|
||||
log.Info("gracefully stopped")
|
||||
}
|
4
go.mod
4
go.mod
@ -3,6 +3,7 @@ module github.com/mxpv/podsync
|
||||
require (
|
||||
cloud.google.com/go v0.25.0 // indirect
|
||||
github.com/BrianHicks/finch v0.0.0-20140409222414-419bd73c29ec
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20170929212804-61590edac4c7
|
||||
github.com/aws/aws-sdk-go v1.15.81
|
||||
github.com/boj/redistore v0.0.0-20160128113310-fc113767cd6b // indirect
|
||||
@ -13,7 +14,6 @@ require (
|
||||
github.com/gin-contrib/gzip v0.0.1
|
||||
github.com/gin-contrib/sessions v0.0.0-20170731012558-a71ea9167c61
|
||||
github.com/gin-gonic/gin v1.3.0
|
||||
github.com/go-chi/chi v4.0.2+incompatible
|
||||
github.com/go-pg/pg v6.14.2+incompatible
|
||||
github.com/golang/mock v1.2.0
|
||||
github.com/gorilla/sessions v1.1.1 // indirect
|
||||
@ -38,3 +38,5 @@ require (
|
||||
google.golang.org/appengine v1.1.0 // indirect
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
4
go.sum
4
go.sum
@ -2,6 +2,8 @@ cloud.google.com/go v0.25.0 h1:6vD6xZTc8Jo6To8gHxFDRVsMvWFDgY3rugNszcDalN8=
|
||||
cloud.google.com/go v0.25.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BrianHicks/finch v0.0.0-20140409222414-419bd73c29ec h1:1VPruZMM1WQC7POhjxbZOWK564cuFz1hlpwYW6ocM4E=
|
||||
github.com/BrianHicks/finch v0.0.0-20140409222414-419bd73c29ec/go.mod h1:+hWo/MWgY8VtjZvdrYM2nPRMaK40zX2iPsH/qD0+Xs0=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20170929212804-61590edac4c7 h1:Clo7QBZv+fHzjCgVp4ELlbIsY5rScCmj+4VCfoMfqtQ=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20170929212804-61590edac4c7/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
|
||||
github.com/aws/aws-sdk-go v1.15.81 h1:va7uoFaV9uKAtZ6BTmp1u7paoMsizYRRLvRuoC07nQ8=
|
||||
@ -30,8 +32,6 @@ github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cou
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-pg/pg v6.14.2+incompatible h1:FrOgsHDUhC3V3wkBGAIN5LVj4nJczFPyy1YNFnetfIQ=
|
||||
github.com/go-pg/pg v6.14.2+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
|
64
pkg/config/config.go
Normal file
64
pkg/config/config.go
Normal file
@ -0,0 +1,64 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Feed is a configuration for a feed
|
||||
type Feed struct {
|
||||
// URL is a full URL of the field
|
||||
URL string `toml:"url"`
|
||||
// PageSize is the number of pages to query from YouTube API.
|
||||
// NOTE: larger page sizes/often requests might drain your API token.
|
||||
PageSize int `toml:"page_size"`
|
||||
// UpdatePeriod is how often to check for updates.
|
||||
// Format is "300ms", "1.5h" or "2h45m".
|
||||
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||
// NOTE: too often update check might drain your API token.
|
||||
UpdatePeriod Duration `toml:"update_period"`
|
||||
}
|
||||
|
||||
type Tokens struct {
|
||||
// YouTube API key.
|
||||
// See https://developers.google.com/youtube/registering_an_application
|
||||
YouTube string `toml:"youtube"`
|
||||
// Vimeo developer key.
|
||||
// See https://developer.vimeo.com/api/guides/start#generate-access-token
|
||||
Vimeo string `toml:"vimeo"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// DataDir is a path to a directory to keep XML feeds and downloaded episodes
|
||||
DataDir string `toml:"data_dir"`
|
||||
// Port is a server port to listen to
|
||||
Port int `toml:"port"`
|
||||
// Feeds is a list of feeds to host by this app.
|
||||
// ID will be used as feed ID in http://podsync.net/{FEED_ID}.xml
|
||||
Feeds map[string]Feed
|
||||
// Tokens is API keys to use to access YouTube/Vimeo APIs.
|
||||
Tokens Tokens `toml:"tokens"`
|
||||
}
|
||||
|
||||
// LoadConfig loads TOML configuration from a file path
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
config := Config{}
|
||||
_, err := toml.DecodeFile(path, &config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to load config file %q", path)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalText(text []byte) error {
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(string(text))
|
||||
return err
|
||||
}
|
53
pkg/config/config_test.go
Normal file
53
pkg/config/config_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
const file = `
|
||||
data_dir = "test/data/"
|
||||
port = 80
|
||||
|
||||
[tokens]
|
||||
youtube = "123"
|
||||
vimeo = "321"
|
||||
|
||||
[feeds]
|
||||
[feeds.XYZ]
|
||||
url = "https://youtube.com/watch?v=ygIUF678y40"
|
||||
page_size = 50
|
||||
update_period = "5h"
|
||||
`
|
||||
|
||||
f, err := ioutil.TempFile("", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err = f.WriteString(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
config, err := LoadConfig(f.Name())
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, config)
|
||||
|
||||
assert.Equal(t, "test/data/", config.DataDir)
|
||||
assert.EqualValues(t, 80, config.Port)
|
||||
|
||||
assert.Equal(t, "123", config.Tokens.YouTube)
|
||||
assert.Equal(t, "321", config.Tokens.Vimeo)
|
||||
|
||||
assert.Len(t, config.Feeds, 1)
|
||||
feed, ok := config.Feeds["XYZ"]
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "https://youtube.com/watch?v=ygIUF678y40", feed.URL)
|
||||
assert.EqualValues(t, 50, feed.PageSize)
|
||||
assert.EqualValues(t, Duration{5 * time.Hour}, feed.UpdatePeriod)
|
||||
}
|
Reference in New Issue
Block a user