Commit 044a4fc9 authored by ale's avatar ale

Update radioctl for the new APIs

parent 10cfbc65
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
......@@ -9,14 +10,21 @@ import (
"os"
"strconv"
"strings"
"time"
"git.autistici.org/ale/autoradio"
"git.autistici.org/ale/autoradio/client"
pb "git.autistici.org/ale/autoradio/proto"
"github.com/gonuts/commander"
gonutsflag "github.com/gonuts/flag"
"go.etcd.io/etcd/clientv3"
)
// Format for output of structured data.
var outputFormat = flag.String("format", "txt", "Output format for structured data (json, txt)")
var (
etcdEndpoints = flag.String("etcd", "http://localhost:2379", "Etcd endpoints (comma-separated list of URLs)")
outputFormat = flag.String("format", "txt", "Output format for structured data (json, txt)")
)
type optionalValue struct {
isSet bool
......@@ -135,15 +143,27 @@ func (b *BaseCommand) Command() *commander.Command {
func (b *BaseCommand) Run(args []string) {
}
func getClient() *autoradio.Client {
return autoradio.NewClient(autoradio.NewEtcdClient(false))
var auClient *client.Client
func getClient() *client.Client {
if auClient == nil {
cli, err := clientv3.New(clientv3.Config{
Endpoints: strings.Split(*etcdEndpoints, ","),
DialTimeout: 5 * time.Second,
})
if err != nil {
log.Fatalf("failed to connect to etcd: %v", err)
}
auClient = client.New(cli)
}
return auClient
}
func setRelay(m *autoradio.Mount, relayUrl string) {
func setRelay(m *pb.Mount, relayUrl string) {
if relayUrl == "" {
// Randomly generate source credentials.
m.Username = autoradio.GenerateUsername(m.Name)
m.Password = autoradio.GeneratePassword()
m.SourceUsername = autoradio.GenerateUsername(m.Path)
m.SourcePassword = autoradio.GeneratePassword()
} else {
// Validate the given relay URL.
u, err := url.Parse(relayUrl)
......@@ -151,30 +171,30 @@ func setRelay(m *autoradio.Mount, relayUrl string) {
log.Fatal(err)
}
m.RelayUrl = u.String()
m.Username = ""
m.Password = ""
m.SourceUsername = ""
m.SourcePassword = ""
}
}
func printMount(m *autoradio.Mount) {
func printMount(m *pb.Mount) {
switch *outputFormat {
case "json":
s, _ := json.MarshalIndent(m, "", " ")
os.Stdout.Write(s)
case "txt":
fmt.Printf("path=%s\n", m.Name)
if m.Username != "" {
fmt.Printf("username=%s\npassword=%s\n", m.Username, m.Password)
fmt.Printf("path=%s\n", m.Path)
if m.SourceUsername != "" {
fmt.Printf("username=%s\npassword=%s\n", m.SourceUsername, m.SourcePassword)
}
if m.RelayUrl != "" {
fmt.Printf("relay_url=%s\n", m.RelayUrl)
}
if m.Fallback != "" {
fmt.Printf("fallback_url=%s\n", m.Fallback)
if m.FallbackPath != "" {
fmt.Printf("fallback_url=%s\n", m.FallbackPath)
}
if t := m.Transcoding; t != nil {
fmt.Printf("transcode_source_url=%s\n", t.SourceName)
if t := m.TranscodeParams; t != nil {
fmt.Printf("transcode_source_url=%s\n", t.SourcePath)
fmt.Printf("transcode_format=%s\n", t.Format)
fmt.Printf("transcode_bitrate=%d\n", t.BitRate)
fmt.Printf("transcode_quality=%f\n", t.Quality)
......@@ -186,8 +206,8 @@ func printMount(m *autoradio.Mount) {
}
}
func mountExists(name string, client *autoradio.Client) bool {
m, _ := client.GetMount(name)
func mountExists(name string, c *client.Client) bool {
m, _ := c.GetMount(context.Background(), name)
return m != nil
}
......@@ -229,22 +249,22 @@ func (cmd *createMountCommand) Run(args []string) {
}
// Check if the mount already exists.
client := getClient()
if mountExists(path, client) {
c := getClient()
if mountExists(path, c) {
log.Fatal("ERROR: A mount with that name already exists!")
}
// Create the new mount and set the relevant fields (depending
// on the options passed to the command).
m := &autoradio.Mount{Name: path}
m := &pb.Mount{Path: path}
setRelay(m, cmd.relay)
m.Fallback = cmd.fallback
m.FallbackPath = cmd.fallback
if err := m.Valid(); err != nil {
log.Fatalf("ERROR: mount configuration is invalid: %v", err)
}
if err := client.SetMount(m); err != nil {
if err := c.SetMount(context.Background(), m); err != nil {
log.Fatalf("ERROR: creating mount: %v", err)
}
......@@ -254,8 +274,15 @@ func (cmd *createMountCommand) Run(args []string) {
// Create a submount (transcoded stream).
type createTranscodingMountCommand struct {
BaseCommand
params *autoradio.EncodingParams
fallback string
sourcePath string
format string
quality float64
bitRate int
sampleRate int
channels int
stereoMode string
fallback string
}
func newCreateTranscodingMountCommand() *createTranscodingMountCommand {
......@@ -268,22 +295,17 @@ Create a new stream that will transcode the parent stream with
different encoding parameters.
`,
},
params: autoradio.NewEncodingParams(),
}
}
func addEncodingFlags(f *gonutsflag.FlagSet, p *autoradio.EncodingParams) {
f.StringVar(&p.SourceName, "source", "", "Source mountpoint")
f.StringVar(&p.Format, "codec", p.Format, "Encoding format")
f.Float64Var(&p.Quality, "quality", p.Quality, "Quality (for VBR encoders)")
f.IntVar(&p.BitRate, "bitrate", p.BitRate, "Bitrate (kbps)")
f.IntVar(&p.SampleRate, "samplerate", p.SampleRate, "Sample rate (Hz)")
f.IntVar(&p.Channels, "channels", p.Channels, "Number of channels")
f.StringVar(&p.StereoMode, "stereo-mode", p.StereoMode, "Stereo mode for mp3 codec (stereo, joint_stereo)")
}
func (cmd *createTranscodingMountCommand) AddFlags(f *gonutsflag.FlagSet) {
addEncodingFlags(f, cmd.params)
f.StringVar(&cmd.sourcePath, "source", "", "Source mountpoint")
f.StringVar(&cmd.format, "codec", "mp3", "Encoding format")
f.Float64Var(&cmd.quality, "quality", 0, "Quality (for VBR encoders)")
f.IntVar(&cmd.bitRate, "bitrate", 32, "Bitrate (kbps)")
f.IntVar(&cmd.sampleRate, "samplerate", 44100, "Sample rate (Hz)")
f.IntVar(&cmd.channels, "channels", 2, "Number of channels")
f.StringVar(&cmd.stereoMode, "stereo-mode", "joint_stereo", "Stereo mode for mp3 codec (stereo, joint_stereo)")
f.StringVar(&cmd.fallback, "fallback", "", "Fallback stream URL")
}
......@@ -299,28 +321,37 @@ func (cmd *createTranscodingMountCommand) Run(args []string) {
}
// The mount path should not exist.
client := getClient()
if mountExists(path, client) {
c := getClient()
if mountExists(path, c) {
log.Fatal("ERROR: a mount with that name already exists!")
}
// The source mount should exist.
if !mountExists(cmd.params.SourceName, client) {
if !mountExists(cmd.sourcePath, c) {
log.Fatal("ERROR: the source mount does not exist!")
}
// Retrieve the parent mount point and add a TranscodingMount.
m := &autoradio.Mount{
Name: path,
Transcoding: cmd.params,
m := &pb.Mount{
Path: path,
FallbackPath: cmd.fallback,
Transcode: true,
TranscodeParams: &pb.EncodingParams{
SourcePath: cmd.sourcePath,
Format: cmd.format,
BitRate: int32(cmd.bitRate),
SampleRate: int32(cmd.sampleRate),
Channels: int32(cmd.channels),
StereoMode: cmd.stereoMode,
Quality: float32(cmd.quality),
},
}
setRelay(m, "")
m.Fallback = cmd.fallback
if err := m.Valid(); err != nil {
log.Fatalf("ERROR: mount configuration is invalid: %v", err)
}
if err := client.SetMount(m); err != nil {
if err := c.SetMount(context.Background(), m); err != nil {
log.Fatalf("ERROR: creating mount: %v", err)
}
......@@ -402,8 +433,8 @@ func (cmd *editMountCommand) Run(args []string) {
log.Fatal("Wrong number of arguments")
}
client := getClient()
m, err := client.GetMount(args[0])
c := getClient()
m, err := c.GetMount(context.Background(), args[0])
if err != nil {
log.Fatalf("ERROR: %v", err)
}
......@@ -413,43 +444,43 @@ func (cmd *editMountCommand) Run(args []string) {
// Only set those fields that were passed on the command line.
if cmd.fallback.IsSet() {
m.Fallback = cmd.fallback.Value()
m.FallbackPath = cmd.fallback.Value()
}
if cmd.relay.IsSet() {
setRelay(m, cmd.relay.Value())
}
if cmd.transcodingOptionsSet() && m.Transcoding == nil {
if cmd.transcodingOptionsSet() && !m.Transcode {
log.Fatal("ERROR: can't set transcoding options on a non-transcoding mount (delete and re-create)")
}
if cmd.transFormat.IsSet() {
m.Transcoding.Format = cmd.transFormat.Value()
m.TranscodeParams.Format = cmd.transFormat.Value()
}
if cmd.transSource.IsSet() {
m.Transcoding.SourceName = cmd.transSource.Value()
m.TranscodeParams.SourcePath = cmd.transSource.Value()
}
if cmd.transBitRate.IsSet() {
m.Transcoding.BitRate = cmd.transBitRate.Value()
m.TranscodeParams.BitRate = int32(cmd.transBitRate.Value())
}
if cmd.transSampleRate.IsSet() {
m.Transcoding.SampleRate = cmd.transSampleRate.Value()
m.TranscodeParams.SampleRate = int32(cmd.transSampleRate.Value())
}
if cmd.transQuality.IsSet() {
m.Transcoding.Quality = cmd.transQuality.Value()
m.TranscodeParams.Quality = float32(cmd.transQuality.Value())
}
if cmd.transChannels.IsSet() {
m.Transcoding.Channels = cmd.transChannels.Value()
m.TranscodeParams.Channels = int32(cmd.transChannels.Value())
}
if cmd.transStereoMode.IsSet() {
m.Transcoding.StereoMode = cmd.transStereoMode.Value()
m.TranscodeParams.StereoMode = cmd.transStereoMode.Value()
}
if err := m.Valid(); err != nil {
log.Fatalf("ERROR: mount configuration is invalid: %v", err)
}
if err := client.SetMount(m); err != nil {
if err := c.SetMount(context.Background(), m); err != nil {
log.Fatalf("ERROR: updating mount: %v", err)
}
......@@ -478,25 +509,25 @@ func (cmd *deleteMountCommand) Run(args []string) {
log.Fatal("Wrong number of arguments")
}
path := args[0]
client := getClient()
if !mountExists(path, client) {
c := getClient()
if !mountExists(path, c) {
log.Fatal("ERROR: mount not found")
}
if err := client.DelMount(path); err != nil {
if err := c.DeleteMount(context.Background(), path); err != nil {
log.Fatalf("ERROR: deleting mount: %v", err)
}
// Delete all the transcoding mounts that have this as a
// source.
mounts, err := client.ListMounts()
mounts, err := c.ListMounts(context.Background())
if err != nil {
log.Fatalf("ERROR: %v", err)
}
for _, m := range mounts {
if m.HasTranscoder() && m.Transcoding.SourceName == path {
if err := client.DelMount(m.Name); err != nil {
log.Printf("ERROR: deleting transcoded mount %s: %v", m.Name, err)
if m.HasTranscoder() && m.TranscodeParams.SourcePath == path {
if err := c.DeleteMount(context.Background(), m.Path); err != nil {
log.Printf("ERROR: deleting transcoded mount %s: %v", m.Path, err)
}
}
}
......@@ -526,13 +557,13 @@ func (cmd *listMountsCommand) Run(args []string) {
log.Fatal("Too many arguments")
}
mounts, err := getClient().ListMounts()
mounts, err := getClient().ListMounts(context.Background())
if err != nil {
log.Fatalf("ERROR: %v", err)
}
var names []string
for _, m := range mounts {
names = append(names, m.Name)
names = append(names, m.Path)
}
switch *outputFormat {
......@@ -571,7 +602,7 @@ func (cmd *showMountCommand) Run(args []string) {
log.Fatal("Wrong number of arguments")
}
m, err := getClient().GetMount(args[0])
m, err := getClient().GetMount(context.Background(), args[0])
if err != nil {
log.Fatalf("ERROR: %v", err)
}
......@@ -605,7 +636,7 @@ func (cmd *backupCommand) Run(args []string) {
log.Fatal("Too many arguments")
}
mounts, err := getClient().ListMounts()
mounts, err := getClient().ListMounts(context.Background())
if err != nil {
log.Fatalf("ERROR: %v", err)
}
......@@ -636,15 +667,15 @@ func (cmd *restoreCommand) Run(args []string) {
log.Fatal("Too many arguments")
}
var mounts []*autoradio.Mount
var mounts []*pb.Mount
if err := json.NewDecoder(os.Stdin).Decode(&mounts); err != nil {
log.Fatalf("ERROR: %v", err)
}
client := getClient()
c := getClient()
for _, m := range mounts {
if err := client.SetMount(m); err != nil {
log.Printf("ERROR: creating mount %s: %v", m.Name, err)
if err := c.SetMount(context.Background(), m); err != nil {
log.Printf("ERROR: creating mount %s: %v", m.Path, err)
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment