Skip to content

Commit

Permalink
feat: implement broadcaster and recorder
Browse files Browse the repository at this point in the history
  • Loading branch information
anilmisirlioglu committed Feb 4, 2022
1 parent ca313dc commit 5c40295
Show file tree
Hide file tree
Showing 17 changed files with 562 additions and 24 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@

# Dependency directories (remove the comment below to include it)
# vendor/

# Other
.idea
out
59 changes: 59 additions & 0 deletions cmd/broadcast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"github.com/racing-telemetry/f1-dump/internal/text/emoji"
"github.com/racing-telemetry/f1-dump/internal/text/printer"
"github.com/racing-telemetry/f1-dump/pkg/broadcaster"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
)

var broadcastCmd = &cobra.Command{
Use: "broadcast",
Short: "Start broadcasting",
Long: `Start broadcasting`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
flags, err := buildFlags(cmd)
if err != nil {
return printer.Error(err)
}

b, err := broadcaster.NewBroadcaster(flags.UDPAddr())
if err != nil {
return printer.Error(err)
}

// wait exit signal, ctrl+c to early exit
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

go func() {
<-c

b.Stop()
printer.Print(emoji.Rocket, "%d packs have been published", b.Stats.RecvCount())

os.Exit(0)
}()

printer.Print(emoji.Sparkless, "Broadcast started at %s:%d, press Ctrl+C to stop", flags.host, flags.port)
err = b.Start(flags.file)
if err != nil {
return printer.Error(err)
}

b.Stop()
printer.Print(emoji.Rocket, "%d packs have been published", b.Stats.RecvCount())

return nil
},
}

func init() {
addFlags(broadcastCmd)

rootCmd.AddCommand(broadcastCmd)
}
67 changes: 67 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cmd

import (
"errors"
"fmt"
"github.com/racing-telemetry/f1-dump/internal"
"github.com/spf13/cobra"
"net"
"os"
"path/filepath"
"strings"
)

type Flags struct {
port int
host string
file string
}

func (f *Flags) UDPAddr() *net.UDPAddr {
return &net.UDPAddr{
IP: net.ParseIP(f.host),
Port: f.port,
}
}

func addFlags(cmd *cobra.Command) {
cmd.Flags().IntP("port", "p", internal.DefaultPort, "Port address to listen on UDP.")
cmd.Flags().String("ip", internal.DefaultHost, "Address to listen on UDP.")
cmd.Flags().StringP("file", "f", "", "I/O file path or name to save and read packets. (sample: foo/bar/output.bin)")
}

func buildFlags(cmd *cobra.Command) (*Flags, error) {
port, err := cmd.Flags().GetInt("port")
if err != nil {
return nil, err
}

host, _ := cmd.Flags().GetString("ip")
if host == "" {
host = internal.DefaultHost
}

path, _ := cmd.Flags().GetString("file")
path = strings.TrimSpace(path)
if path != "" {
ext := filepath.Ext(path)
if ext != ".bin" {
return nil, errors.New("file extension must be ends with .bin")
}

_, err = os.Stat(path)
switch cmd.Name() {
case "record":
if err == nil {
return nil, fmt.Errorf("file already exists: %s", path)
}

case "broadcast":
if err != nil {
return nil, fmt.Errorf("file doesnt exist: %s", path)
}
}
}

return &Flags{port: port, host: host, file: path}, nil
}
75 changes: 75 additions & 0 deletions cmd/record.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cmd

import (
"errors"
"fmt"
"github.com/dustin/go-humanize"
"github.com/racing-telemetry/f1-dump/internal/text/emoji"
"github.com/racing-telemetry/f1-dump/internal/text/printer"
"github.com/racing-telemetry/f1-dump/pkg/recorder"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
)

var cmdRecord = &cobra.Command{
Use: "record",
Short: "Start recording packets from UDP source.",
Long: `Start recording packets from UDP source.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
flags, err := buildFlags(cmd)
if err != nil {
return printer.Error(err)
}

rc, err := recorder.NewRecorder(flags.UDPAddr())
if err != nil {
return fmt.Errorf("%s\n%s", printer.Error(errors.New("recorder can't create")), printer.Error(err))
}

// wait exit signal, ctrl+c to exit
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

go func() {
<-c

rc.Stop()

f, err := rc.Save(flags.file)
if err != nil {
printer.PrintError(err.Error())
} else {
stat, err := f.Stat()
if err != nil {
printer.PrintError(err.Error())
}

printer.Print(emoji.File, "File saved to %s (size: %s)", f.Name(), humanize.Bytes(uint64(stat.Size())))

err = f.Close()
if err != nil {
printer.PrintError(err.Error())
}
}

printer.Print(emoji.Rocket, "Received Packets: %d", rc.Stats.RecvCount())
printer.Print(emoji.Construction, "Lost Packets: %d", rc.Stats.ErrCount())

os.Exit(0)
}()

printer.Print(emoji.Sparkless, "Record started at %s:%d, press Ctrl+C to stop", flags.host, flags.port)
rc.Start()

return nil
},
}

func init() {
addFlags(cmdRecord)

rootCmd.AddCommand(cmdRecord)
}
7 changes: 7 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"github.com/racing-telemetry/f1-dump/pkg/opts"
"github.com/spf13/cobra"
"os"
)
Expand All @@ -16,3 +17,9 @@ func Execute() {
os.Exit(1)
}
}

func init() {
rootCmd.CompletionOptions.DisableDefaultCmd = true

rootCmd.PersistentFlags().BoolVarP(&opts.Verbose, "verbose", "v", false, "verbose output")
}
39 changes: 17 additions & 22 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package cmd

import (
"encoding/json"
"errors"
"fmt"
"github.com/pkg/errors"
"github.com/racing-telemetry/f1-dump/internal"
"github.com/racing-telemetry/f1-dump/internal/text/printer"
"github.com/spf13/cobra"
"runtime"
)
Expand All @@ -23,26 +24,6 @@ type CLIVersionInfo struct {
Platform string
}

func NewCmdVersion() *cobra.Command {
cmd := &cobra.Command{
Use: "version",
Short: "Prints the CLI version",
Long: `Prints the CLI version`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
bytes, err := json.Marshal(VersionInfo())
if err != nil {
return errors.Wrap(err, "failed to marshal version info")
}

fmt.Println(string(bytes))
return nil
},
}

return cmd
}

func VersionInfo() *CLIVersionInfo {
return &CLIVersionInfo{
Version: internal.Version,
Expand All @@ -55,5 +36,19 @@ func VersionInfo() *CLIVersionInfo {
}

func init() {
rootCmd.AddCommand(NewCmdVersion())
rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Prints the CLI version",
Long: "Prints the CLI version",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
bytes, err := json.Marshal(VersionInfo())
if err != nil {
return printer.Error(errors.New("failed to marshal version info"))
}

fmt.Println(string(bytes))
return nil
},
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/racing-telemetry/f1-dump
go 1.17

require (
github.com/pkg/errors v0.8.1
github.com/dustin/go-humanize v1.0.0
github.com/spf13/cobra v1.3.0
)

Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down Expand Up @@ -273,7 +275,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
10 changes: 10 additions & 0 deletions internal/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package internal

const (
DefaultPort = 20777
DefaultHost = "localhost"
)

const BufferSize = 1024 + 1024/2

const OutFileFormat = "f1-out-%d.bin"
12 changes: 12 additions & 0 deletions internal/text/emoji/emoji.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package emoji

type Emoji rune

const (
Boom Emoji = '💥'
Fire Emoji = '🔥'
Sparkless Emoji = '✨'
File Emoji = '📁'
Construction Emoji = '🚧'
Rocket Emoji = '🚀'
)
18 changes: 18 additions & 0 deletions internal/text/printer/printer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package printer

import (
"fmt"
"github.com/racing-telemetry/f1-dump/internal/text/emoji"
)

func Print(emoji emoji.Emoji, s string, a ...interface{}) {
fmt.Printf("\r%s %s\n", string(emoji), fmt.Sprintf(s, a...))
}

func Error(err error) error {
return fmt.Errorf("\r%s Error: %s", string(emoji.Boom), err.Error())
}

func PrintError(format string, a ...interface{}) {
fmt.Println(Error(fmt.Errorf(format, a...)))
}
33 changes: 33 additions & 0 deletions internal/udp/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package udp

import (
"github.com/racing-telemetry/f1-dump/internal"
"net"
)

type Client struct {
conn *net.UDPConn
}

func Serve(addr *net.UDPAddr) (*Client, error) {
conn, err := net.ListenUDP("udp", addr)
if err != nil {
return nil, err
}

return &Client{conn: conn}, nil
}

func (c *Client) ReadSocket() ([]byte, error) {
buf := make([]byte, internal.BufferSize)
_, _, err := c.conn.ReadFromUDP(buf)
if err != nil {
return nil, err
}

return buf, err
}

func (c *Client) Close() error {
return c.conn.Close()
}
Loading

0 comments on commit 5c40295

Please sign in to comment.