You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
3.9 KiB
Go

package iperf
import (
"context"
"encoding/json"
"fmt"
"github.com/google/uuid"
"io"
"strings"
"time"
)
var (
defaultPort = 5201
defaultInterval = 1
defaultJSON = true
)
func NewServer() *Server {
s := &Server{
Options: &ServerOptions{
Port: &defaultPort,
Interval: &defaultInterval,
JSON: &defaultJSON,
},
}
s.Id = uuid.New().String()
return s
}
type ServerOptions struct {
OneOff *bool `json:"one_off" yaml:"one_off" xml:"one_off"`
Port *int `json:"port" yaml:"port" xml:"port"`
Format *rune `json:"format" yaml:"format" xml:"format"`
Interval *int `json:"interval" yaml:"interval" xml:"interval"`
JSON *bool `json:"json" yaml:"json" xml:"json"`
LogFile *string `json:"log_file" yaml:"log_file" xml:"log_file"`
}
type Server struct {
Id string `json:"id" yaml:"id" xml:"id"`
Running bool `json:"running" yaml:"running" xml:"running"`
Options *ServerOptions `json:"-" yaml:"-" xml:"-"`
ExitCode *int `json:"exit_code" yaml:"exit_code" xml:"exit_code"`
Debug bool `json:"-" yaml:"-" xml:"-"`
outputStream io.ReadCloser `json:"output_stream" yaml:"output_stream" xml:"output_stream"`
errorStream io.ReadCloser `json:"error_stream" yaml:"error_stream" xml:"error_stream"`
cancel context.CancelFunc `json:"cancel" yaml:"cancel" xml:"cancel"`
}
func (s *Server) LoadOptionsJSON(jsonStr string) (err error) {
return json.Unmarshal([]byte(jsonStr), s.Options)
}
func (s *Server) LoadOptions(options *ServerOptions) {
s.Options = options
}
func (s *Server) commandString() (cmd string, err error) {
builder := strings.Builder{}
fmt.Fprintf(&builder, "%s -s", binaryLocation)
if s.Options.OneOff != nil && s.OneOff() == true {
builder.WriteString(" --one-off")
}
if s.Options.Port != nil {
fmt.Fprintf(&builder, " --port %d", s.Port())
}
if s.Options.Format != nil {
fmt.Fprintf(&builder, " --format %c", s.Format())
}
if s.Options.Interval != nil {
fmt.Fprintf(&builder, " --interval %d", s.Interval())
}
if s.Options.JSON != nil && s.JSON() == true {
builder.WriteString(" --json")
}
if s.Options.LogFile != nil && s.LogFile() != "" {
fmt.Fprintf(&builder, " --logfile %s --forceflush", s.LogFile())
}
return builder.String(), nil
}
func (s *Server) OneOff() bool {
if s.Options.OneOff == nil {
return false
}
return *s.Options.OneOff
}
func (s *Server) SetOneOff(oneOff bool) {
s.Options.OneOff = &oneOff
}
func (s *Server) Port() int {
if s.Options.Port == nil {
return defaultPort
}
return *s.Options.Port
}
func (s *Server) SetPort(port int) {
s.Options.Port = &port
}
func (s *Server) Format() rune {
if s.Options.Format == nil {
return ' '
}
return *s.Options.Format
}
func (s *Server) SetFormat(format rune) {
s.Options.Format = &format
}
func (s *Server) Interval() int {
if s.Options.Interval == nil {
return defaultInterval
}
return *s.Options.Interval
}
func (s *Server) JSON() bool {
if s.Options.JSON == nil {
return false
}
return *s.Options.JSON
}
func (s *Server) SetJSON(json bool) {
s.Options.JSON = &json
}
func (s *Server) LogFile() string {
if s.Options.LogFile == nil {
return ""
}
return *s.Options.LogFile
}
func (s *Server) SetLogFile(filename string) {
s.Options.LogFile = &filename
}
func (s *Server) Start() (err error) {
cmd, err := s.commandString()
if err != nil {
return err
}
var exit chan int
s.outputStream, s.errorStream, exit, s.cancel, err = ExecuteAsyncWithCancel(cmd)
if err != nil {
return err
}
s.Running = true
go func() {
ds := DebugScanner{Silent: !s.Debug}
ds.Scan(s.outputStream)
}()
go func() {
ds := DebugScanner{Silent: !s.Debug}
ds.Scan(s.errorStream)
}()
go func() {
exitCode := <-exit
s.ExitCode = &exitCode
s.Running = false
}()
return nil
}
func (s *Server) Stop() {
if s.Running && s.cancel != nil {
s.cancel()
time.Sleep(100 * time.Millisecond)
}
}