This commit is contained in:
Gregory Salaun 2024-09-24 11:57:48 +07:00
parent 9ddc3ce347
commit ab17255bdc
11 changed files with 912 additions and 194790 deletions

BIN
FlexDXCluster.exe Normal file

Binary file not shown.

View File

@ -13,7 +13,7 @@ import (
var spotRe *regexp.Regexp = regexp.MustCompile(`DX\sde\s([\w\d]+).*:\s+(\d+.\d)\s+([\w\d]+)\s+(CW|SSB|FT8|FT4|RTTY|USB|LSB)?\s+(.*)\s\s\s+([\d]+\w{1})`) var spotRe *regexp.Regexp = regexp.MustCompile(`DX\sde\s([\w\d]+).*:\s+(\d+.\d)\s+([\w\d]+)\s+(CW|SSB|FT8|FT4|RTTY|USB|LSB)?\s+(.*)\s\s\s+([\d]+\w{1})`)
type TelnetClient struct { type TCPClient struct {
Login string Login string
Password string Password string
Address string Address string
@ -31,89 +31,107 @@ type TelnetClient struct {
Log *log.Logger Log *log.Logger
} }
func (tc *TelnetClient) setDefaultParams() { func NewTCPClient(cfg Config, TCPServer *TCPServer, FlexClient *FlexClient, log *log.Logger) *TCPClient {
if tc.Timeout == 0 { return &TCPClient{
tc.Timeout = 600 * time.Second Address: Cfg.Cluster.Server,
} Port: Cfg.Cluster.Port,
if tc.LogWriter == nil { Login: Cfg.Cluster.Login,
tc.LogWriter = bufio.NewWriter(os.Stdout) MsgChan: TCPServer.MsgChan,
CmdChan: TCPServer.CmdChan,
SpotChan: FlexClient.SpotChan,
Log: log,
TCPServer: *TCPServer,
FlexClient: *FlexClient,
} }
} }
func (tc *TelnetClient) StartClient() { func (c *TCPClient) setDefaultParams() {
if c.Timeout == 0 {
c.Timeout = 600 * time.Second
}
if c.LogWriter == nil {
c.LogWriter = bufio.NewWriter(os.Stdout)
}
}
func (c *TCPClient) StartClient() {
var err error var err error
addr, err := net.ResolveTCPAddr("tcp", tc.Address+":"+tc.Port) addr, err := net.ResolveTCPAddr("tcp", c.Address+":"+c.Port)
if err != nil { if err != nil {
tc.Log.Error("cannot resolve Telnet Client address:", err) c.Log.Error("cannot resolve Telnet Client address:", err)
} }
tc.setDefaultParams() c.setDefaultParams()
tc.Conn, err = net.DialTCP("tcp", nil, addr) c.Conn, err = net.DialTCP("tcp", nil, addr)
if err != nil { if err != nil {
tc.Log.Error("cannot connect to Telnet Client:", err) c.Log.Error("cannot connect to Telnet Client:", err)
} }
tc.Log.Infof("connected to %s:%s", tc.Address, tc.Port) c.Log.Infof("connected to %s:%s", c.Address, c.Port)
err = tc.Conn.SetKeepAlive(true) err = c.Conn.SetKeepAlive(true)
if err != nil { if err != nil {
tc.Log.Error("error while setting keep alive:", err) c.Log.Error("error while setting keep alive:", err)
} }
tc.Reader = bufio.NewReader(tc.Conn) c.Reader = bufio.NewReader(c.Conn)
tc.Writer = bufio.NewWriter(tc.Conn) c.Writer = bufio.NewWriter(c.Conn)
go tc.ReadLine() go c.ReadLine()
} }
func (tc *TelnetClient) Close() { func (c *TCPClient) Close() {
tc.Writer.WriteString("bye") c.Writer.WriteString("bye")
} }
func (tc *TelnetClient) SetFilters() { func (c *TCPClient) SetFilters() {
if Cfg.Cluster.FT8 { if Cfg.Cluster.FT8 {
tc.Write([]byte("set/ft8\r\n")) c.Write([]byte("set/ft8\r\n"))
tc.Log.Info("FT8 is on as defined in the config file") c.Log.Info("FT8 is on as defined in the config file")
} }
if Cfg.Cluster.Skimmer { if Cfg.Cluster.Skimmer {
tc.Write([]byte("set/skimmer\r\n")) c.Write([]byte("set/skimmer\r\n"))
tc.Log.Info("Skimmer is on as defined in the config file") c.Log.Info("Skimmer is on as defined in the config file")
} }
if !Cfg.Cluster.FT8 { if !Cfg.Cluster.FT8 {
tc.Write([]byte("set/noft8\r\n")) c.Write([]byte("set/noft8\r\n"))
tc.Log.Info("FT8 is off as defined in the config file") c.Log.Info("FT8 is off as defined in the config file")
} }
if !Cfg.Cluster.Skimmer { if !Cfg.Cluster.Skimmer {
tc.Write([]byte("set/noskimmer\r\n")) c.Write([]byte("set/noskimmer\r\n"))
tc.Log.Info("Skimmer is off as defined in the config file") c.Log.Info("Skimmer is off as defined in the config file")
} }
} }
func (tc *TelnetClient) ReadLine() { func (c *TCPClient) ReadLine() {
for { for {
message, err := tc.Reader.ReadString('\n') message, err := c.Reader.ReadString('\n')
if err != nil { if err != nil {
tc.Log.Errorf("Error reading message: %s", err) c.Log.Errorf("Error reading message: %s", err)
continue continue
} }
if strings.Contains(message, "Login: \r\n") || strings.Contains(message, "Please enter your call: \r\n") { if strings.Contains(message, "Login: \r\n") || strings.Contains(message, "Please enter your call: \r\n") {
tc.Log.Info("Found login prompt...sending callsign") c.Log.Info("Found login prompt...sending callsign")
tc.Write([]byte(tc.Login + "\r\n")) c.Write([]byte(c.Login + "\r\n"))
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
tc.SetFilters() c.SetFilters()
} }
ProcessTelnetSpot(spotRe, message, tc.SpotChan, tc.Log) ProcessTelnetSpot(spotRe, message, c.SpotChan, c.Log)
tc.MsgChan <- message
// Send the spot message to TCP server
if len(c.TCPServer.Clients) > 0 {
c.MsgChan <- message
}
} }
} }
// Write sends raw data to remove telnet server // Write sends raw data to remove telnet server
func (tc *TelnetClient) Write(data []byte) (n int, err error) { func (tc *TCPClient) Write(data []byte) (n int, err error) {
n, err = tc.Writer.Write(data) n, err = tc.Writer.Write(data)
if err == nil { if err == nil {
err = tc.Writer.Flush() err = tc.Writer.Flush()

View File

@ -50,7 +50,7 @@ func (s *TCPServer) StartServer() {
defer s.Listener.Close() defer s.Listener.Close()
s.Log.Info("telnet server listening on %s:%s", Cfg.Telnet.Host, Cfg.Telnet.Port) s.Log.Infof("telnet server listening on %s:%s", Cfg.Telnet.Host, Cfg.Telnet.Port)
go func() { go func() {
for message := range s.MsgChan { for message := range s.MsgChan {
@ -74,39 +74,43 @@ func (s *TCPServer) StartServer() {
} }
func (s *TCPServer) handleConnection() { func (s *TCPServer) handleConnection() {
defer s.Conn.Close()
s.Conn.Write([]byte("Welcome to the FlexDXCluster telnet server! Type 'bye' to exit.\n")) s.Conn.Write([]byte("Welcome to the FlexDXCluster telnet server! Type 'bye' to exit.\n"))
// s.Conn.Write([]byte(`To ALL de XV9Q <0234Z> : Clicked on "JH2UNG"\n`)) s.Reader = bufio.NewReader(s.Conn)
s.Writer = bufio.NewWriter(s.Conn)
reader := bufio.NewReader(s.Conn)
for { for {
message, err := reader.ReadString('\n') message, err := s.Reader.ReadString('\n')
if err != nil { if err != nil {
s.Mutex.Lock() s.Mutex.Lock()
delete(s.Clients, s.Conn) delete(s.Clients, s.Conn)
s.Mutex.Unlock() s.Mutex.Unlock()
s.Log.Info("client disconnected") s.Log.Infof("client %s disconnected", s.Conn.RemoteAddr().String())
return return
} }
message = strings.TrimSpace(message) message = strings.TrimSpace(message)
if message == "bye" { s.Log.Infof("Message reçu du client: %s\n", message)
switch message {
case "bye":
s.Mutex.Lock() s.Mutex.Lock()
delete(s.Clients, s.Conn) delete(s.Clients, s.Conn)
s.Mutex.Unlock() s.Mutex.Unlock()
s.Log.Info("client disconnected") s.Log.Infof("client %s disconnected", s.Conn.RemoteAddr().String())
return return
case "SH/DX 30":
return
default:
s.Write("cannot identify command\n")
} }
s.Log.Info("Message reçu du client: %s\n", message)
} }
} }
func (s *TCPServer) Write(message string) (n int, err error) { func (s *TCPServer) Write(message string) (n int, err error) {
n, err = s.Writer.Write([]byte(message)) _, err = s.Writer.Write([]byte(message))
if err == nil { if err == nil {
err = s.Writer.Flush() err = s.Writer.Flush()
} }

View File

@ -11,7 +11,7 @@ cluster:
ft8: false ft8: false
flex: flex:
ip: 10.10.10.120 ip: 10.10.10.120
spot_life: 300 spot_life: 600
clublog: clublog:
api: 5767f19333363a9ef432ee9cd4141fe76b8adf38 api: 5767f19333363a9ef432ee9cd4141fe76b8adf38
telnet: telnet:

View File

@ -54,7 +54,7 @@ func NewFlexDXDatabase(filePath string, log *log.Logger) *FlexDXClusterRepositor
`CREATE TABLE IF NOT EXISTS "spots" ( `CREATE TABLE IF NOT EXISTS "spots" (
"id" INTEGER NOT NULL UNIQUE, "id" INTEGER NOT NULL UNIQUE,
"commandNumber" INTEGER NOT NULL UNIQUE, "commandNumber" INTEGER NOT NULL UNIQUE,
"flexSpotNumber" INTEGER UNIQUE, "flexSpotNumber" INTEGER,
"dx" TEXT NOT NULL, "dx" TEXT NOT NULL,
"freqMhz" TEXT, "freqMhz" TEXT,
"freqHz" TEXT, "freqHz" TEXT,
@ -63,6 +63,7 @@ func NewFlexDXDatabase(filePath string, log *log.Logger) *FlexDXClusterRepositor
"spotter" INTEGER, "spotter" INTEGER,
"flexMode" TEXT, "flexMode" TEXT,
"source" TEXT, "source" TEXT,
"time" TEXT,
"timestamp" INTEGER, "timestamp" INTEGER,
"lifeTime" TEXT, "lifeTime" TEXT,
"priority" TEXT, "priority" TEXT,
@ -195,7 +196,7 @@ func (r *FlexDXClusterRepository) FindDXSameBand(spot FlexSpot) (*FlexSpot, erro
s := FlexSpot{} s := FlexSpot{}
for rows.Next() { for rows.Next() {
if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.TimeStamp, &s.LifeTime, &s.Priority, if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.UTCTime, &s.TimeStamp, &s.LifeTime, &s.Priority,
&s.Comment, &s.Color, &s.BackgroundColor); err != nil { &s.Comment, &s.Color, &s.BackgroundColor); err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
@ -205,8 +206,8 @@ func (r *FlexDXClusterRepository) FindDXSameBand(spot FlexSpot) (*FlexSpot, erro
} }
func (r *FlexDXClusterRepository) CreateSpot(spot FlexSpot) { func (r *FlexDXClusterRepository) CreateSpot(spot FlexSpot) {
query := "INSERT INTO `spots` (`commandNumber`, `flexSpotNumber`, `dx`, `freqMhz`, `freqHz`, `band`, `mode`, `spotter`, `flexMode`, `source`, `timestamp`, `lifeTime`, `priority`, `comment`, `color`, `backgroundColor`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" query := "INSERT INTO `spots` (`commandNumber`, `flexSpotNumber`, `dx`, `freqMhz`, `freqHz`, `band`, `mode`, `spotter`, `flexMode`, `source`, `time`, `timestamp`, `lifeTime`, `priority`, `comment`, `color`, `backgroundColor`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
insertResult, err := r.db.ExecContext(context.Background(), query, spot.CommandNumber, spot.CommandNumber, spot.DX, spot.FrequencyMhz, spot.FrequencyHz, spot.Band, spot.Mode, spot.SpotterCallsign, spot.FlexMode, spot.Source, time.Now().Unix(), spot.LifeTime, spot.Priority, spot.Comment, spot.Color, spot.BackgroundColor) insertResult, err := r.db.ExecContext(context.Background(), query, spot.CommandNumber, spot.CommandNumber, spot.DX, spot.FrequencyMhz, spot.FrequencyHz, spot.Band, spot.Mode, spot.SpotterCallsign, spot.FlexMode, spot.Source, spot.UTCTime, time.Now().Unix(), spot.LifeTime, spot.Priority, spot.Comment, spot.Color, spot.BackgroundColor)
if err != nil { if err != nil {
log.Errorf("cannot insert spot in database: %s", err) log.Errorf("cannot insert spot in database: %s", err)
} }
@ -231,7 +232,7 @@ func (r *FlexDXClusterRepository) FindSpotByCommandNumber(commandNumber string)
s := FlexSpot{} s := FlexSpot{}
for rows.Next() { for rows.Next() {
if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.TimeStamp, &s.LifeTime, &s.Priority, if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.UTCTime, &s.TimeStamp, &s.LifeTime, &s.Priority,
&s.Comment, &s.Color, &s.BackgroundColor); err != nil { &s.Comment, &s.Color, &s.BackgroundColor); err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
@ -249,7 +250,7 @@ func (r *FlexDXClusterRepository) FindSpotByFlexSpotNumber(spotNumber string) (*
s := FlexSpot{} s := FlexSpot{}
for rows.Next() { for rows.Next() {
if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.TimeStamp, &s.LifeTime, &s.Priority, if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.UTCTime, &s.TimeStamp, &s.LifeTime, &s.Priority,
&s.Comment, &s.Color, &s.BackgroundColor); err != nil { &s.Comment, &s.Color, &s.BackgroundColor); err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
@ -258,8 +259,8 @@ func (r *FlexDXClusterRepository) FindSpotByFlexSpotNumber(spotNumber string) (*
return &s, nil return &s, nil
} }
func (r *FlexDXClusterRepository) UpdateFlexSpotNumberByID(flexSpot string, spot FlexSpot) (*FlexSpot, error) { func (r *FlexDXClusterRepository) UpdateFlexSpotNumberByID(flexSpotNumber string, spot FlexSpot) (*FlexSpot, error) {
flexSpotNumberInt, _ := strconv.Atoi(flexSpot) flexSpotNumberInt, _ := strconv.Atoi(flexSpotNumber)
rows, err := r.db.Query(`UPDATE spots SET flexSpotNumber = ? WHERE id = ? RETURNING *`, flexSpotNumberInt, spot.ID) rows, err := r.db.Query(`UPDATE spots SET flexSpotNumber = ? WHERE id = ? RETURNING *`, flexSpotNumberInt, spot.ID)
if err != nil { if err != nil {
r.Log.Errorf("could not update database: %s", err) r.Log.Errorf("could not update database: %s", err)
@ -267,7 +268,7 @@ func (r *FlexDXClusterRepository) UpdateFlexSpotNumberByID(flexSpot string, spot
s := FlexSpot{} s := FlexSpot{}
for rows.Next() { for rows.Next() {
if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.TimeStamp, &s.LifeTime, &s.Priority, if err := rows.Scan(&s.ID, &s.CommandNumber, &s.FlexSpotNumber, &s.DX, &s.FrequencyMhz, &s.FrequencyHz, &s.Band, &s.Mode, &s.SpotterCallsign, &s.FlexMode, &s.Source, &s.UTCTime, &s.TimeStamp, &s.LifeTime, &s.Priority,
&s.Comment, &s.Color, &s.BackgroundColor); err != nil { &s.Comment, &s.Color, &s.BackgroundColor); err != nil {
fmt.Println(err) fmt.Println(err)
return nil, err return nil, err
@ -277,6 +278,15 @@ func (r *FlexDXClusterRepository) UpdateFlexSpotNumberByID(flexSpot string, spot
return &s, nil return &s, nil
} }
func (r *FlexDXClusterRepository) DeleteSpotByFlexSpotNumber(flexSpotNumber string) {
flexSpotNumberInt, _ := strconv.Atoi(flexSpotNumber)
query := "DELETE from spots WHERE flexSpotNumber = ?"
_, err := r.db.Exec(query, flexSpotNumberInt)
if err != nil {
r.Log.Errorf("could not delete spot %v from database", flexSpotNumberInt)
}
}
func DeleteDatabase(filePath string, log *log.Logger) { func DeleteDatabase(filePath string, log *log.Logger) {
_, err := os.Stat(filePath) _, err := os.Stat(filePath)
if !os.IsNotExist(err) { if !os.IsNotExist(err) {

Binary file not shown.

View File

@ -5,14 +5,14 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"strconv" "regexp"
"strings" "strings"
"time" "time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
var command int = 1 var CommandNumber int = 1
type FlexSpot struct { type FlexSpot struct {
ID int ID int
@ -27,6 +27,7 @@ type FlexSpot struct {
Source string Source string
SpotterCallsign string SpotterCallsign string
TimeStamp int64 TimeStamp int64
UTCTime string
LifeTime string LifeTime string
Priority string Priority string
Comment string Comment string
@ -46,10 +47,10 @@ type FlexClient struct {
MsgChan chan string MsgChan chan string
Repo FlexDXClusterRepository Repo FlexDXClusterRepository
Log *log.Logger Log *log.Logger
TCPServer *TCPServer TCPServer TCPServer
} }
func NewFlexClient(repo FlexDXClusterRepository, TCPServer *TCPServer, log *log.Logger) *FlexClient { func NewFlexClient(repo FlexDXClusterRepository, TCPServer TCPServer, log *log.Logger) *FlexClient {
return &FlexClient{ return &FlexClient{
Address: Cfg.Flex.IP, Address: Cfg.Flex.IP,
Port: "4992", Port: "4992",
@ -74,7 +75,7 @@ func (fc *FlexClient) StartFlexClient() {
fc.Timeout = 600 * time.Second fc.Timeout = 600 * time.Second
fc.Conn, err = net.DialTCP("tcp", nil, addr) fc.Conn, err = net.DialTCP("tcp", nil, addr)
if err != nil { if err != nil {
fc.Log.Error("could not dial flex client:", err) fc.Log.Error("could not connect to flex radio, exiting...", err)
os.Exit(1) os.Exit(1)
} }
fc.Log.Infof("connected to %s:%s", fc.Address, fc.Port) fc.Log.Infof("connected to %s:%s", fc.Address, fc.Port)
@ -94,14 +95,22 @@ func (fc *FlexClient) StartFlexClient() {
} }
go fc.ReadLine() go fc.ReadLine()
subSpotAllCmd := fmt.Sprintf("C%v|sub spot all", CommandNumber)
fc.Write(subSpotAllCmd)
CommandNumber++
clrSpotAllCmd := fmt.Sprintf("C%v|spot clear", CommandNumber)
fc.Write(clrSpotAllCmd)
CommandNumber++
} }
func (fc *FlexClient) SendSpottoFlex(spot TelnetSpot) (n int, err error) { func (fc *FlexClient) SendSpottoFlex(spot TelnetSpot) {
freq := FreqMhztoHz(spot.Frequency) freq := FreqMhztoHz(spot.Frequency)
flexSpot := FlexSpot{ flexSpot := FlexSpot{
CommandNumber: command, CommandNumber: CommandNumber,
DX: spot.DX, DX: spot.DX,
FrequencyMhz: freq, FrequencyMhz: freq,
FrequencyHz: spot.Frequency, FrequencyHz: spot.Frequency,
@ -110,6 +119,7 @@ func (fc *FlexClient) SendSpottoFlex(spot TelnetSpot) (n int, err error) {
Source: "FlexDXCluster", Source: "FlexDXCluster",
SpotterCallsign: spot.Spotter, SpotterCallsign: spot.Spotter,
TimeStamp: time.Now().Unix(), TimeStamp: time.Now().Unix(),
UTCTime: spot.Time,
LifeTime: Cfg.Flex.SpotLife, LifeTime: Cfg.Flex.SpotLife,
Comment: spot.Comment, Comment: spot.Comment,
Color: "#eaeaea", Color: "#eaeaea",
@ -149,70 +159,82 @@ func (fc *FlexClient) SendSpottoFlex(spot TelnetSpot) (n int, err error) {
fc.Log.Error("could not find the DX in the database: ", err) fc.Log.Error("could not find the DX in the database: ", err)
} }
var stringSpot string
spotLife, _ := strconv.Atoi(Cfg.Flex.SpotLife)
spotTime := time.Unix(srcFlexSpot.TimeStamp, 0)
elapsed := time.Since(spotTime)
if srcFlexSpot.DX == "" { if srcFlexSpot.DX == "" {
fc.Repo.CreateSpot(flexSpot) fc.Repo.CreateSpot(flexSpot)
stringSpot = fmt.Sprintf("C%v|spot add rx_freq=%v callsign=%s mode=%s source=%s spotter_callsign=%s timestamp=%v lifetime_seconds=%s comment=%s color=%s background_color=%s priority=%s", flexSpot.CommandNumber, flexSpot.FrequencyMhz, stringSpot := fmt.Sprintf("C%v|spot add rx_freq=%v callsign=%s mode=%s source=%s spotter_callsign=%s timestamp=%v lifetime_seconds=%s comment=%s color=%s background_color=%s priority=%s", flexSpot.CommandNumber, flexSpot.FrequencyMhz,
flexSpot.DX, flexSpot.Mode, flexSpot.Source, flexSpot.SpotterCallsign, flexSpot.TimeStamp, flexSpot.LifeTime, flexSpot.Comment, flexSpot.Color, flexSpot.BackgroundColor, flexSpot.Priority) flexSpot.DX, flexSpot.Mode, flexSpot.Source, flexSpot.SpotterCallsign, flexSpot.TimeStamp, flexSpot.LifeTime, flexSpot.Comment, flexSpot.Color, flexSpot.BackgroundColor, flexSpot.Priority)
} else if srcFlexSpot.DX != "" && elapsed > time.Duration(spotLife) { fc.SendSpot(stringSpot)
} else if srcFlexSpot.DX != "" && srcFlexSpot.Band == flexSpot.Band && srcFlexSpot.FrequencyMhz != flexSpot.FrequencyMhz {
fc.Repo.UpdateSpotSameBand(flexSpot) fc.Repo.UpdateSpotSameBand(flexSpot)
stringSpot = fmt.Sprintf("C%v|spot add rx_freq=%v callsign=%s mode=%s source=%s spotter_callsign=%s timestamp=%v lifetime_seconds=%s comment=%s color=%s background_color=%s priority=%s", flexSpot.CommandNumber, flexSpot.FrequencyMhz, stringSpot := fmt.Sprintf("C%v|spot set %v rx_freq=%v callsign=%s mode=%s source=%s spotter_callsign=%s timestamp=%v lifetime_seconds=%s comment=%s color=%s background_color=%s priority=%s", flexSpot.CommandNumber, srcFlexSpot.CommandNumber, flexSpot.FrequencyMhz,
flexSpot.DX, flexSpot.Mode, flexSpot.Source, flexSpot.SpotterCallsign, flexSpot.TimeStamp, flexSpot.LifeTime, flexSpot.Comment, flexSpot.Color, flexSpot.BackgroundColor, flexSpot.Priority)
} else if srcFlexSpot.DX != "" && srcFlexSpot.Band == flexSpot.Band && srcFlexSpot.FrequencyMhz != flexSpot.FrequencyMhz && elapsed < time.Duration(spotLife) {
fc.Repo.UpdateSpotSameBand(flexSpot)
stringSpot = fmt.Sprintf("C%v|spot set %v rx_freq=%v callsign=%s mode=%s source=%s spotter_callsign=%s timestamp=%v lifetime_seconds=%s comment=%s color=%s background_color=%s priority=%s", flexSpot.CommandNumber, srcFlexSpot.CommandNumber, flexSpot.FrequencyMhz,
flexSpot.DX, flexSpot.Mode, flexSpot.Source, flexSpot.SpotterCallsign, flexSpot.TimeStamp, flexSpot.LifeTime, flexSpot.Comment, flexSpot.Color, flexSpot.BackgroundColor, flexSpot.Priority) flexSpot.DX, flexSpot.Mode, flexSpot.Source, flexSpot.SpotterCallsign, flexSpot.TimeStamp, flexSpot.LifeTime, flexSpot.Comment, flexSpot.Color, flexSpot.BackgroundColor, flexSpot.Priority)
CommandNumber++
stringDelete := fmt.Sprintf("C%v|spot remove %v", CommandNumber, srcFlexSpot.FlexSpotNumber)
fc.DeleteAndSendSpot(stringSpot, stringDelete)
} }
fc.Write(stringSpot) CommandNumber++
command++
return
} }
func (fc *FlexClient) SendSpot(stringSpot string) {
fc.Write(stringSpot)
}
func (fc *FlexClient) DeleteAndSendSpot(stringSpot string, deleteSpot string) {
fc.Write(deleteSpot)
fc.Write(stringSpot)
}
func (fc *FlexClient) ReadLine() { func (fc *FlexClient) ReadLine() {
for { for {
message, err := fc.Reader.ReadString(byte('\n')) message, err := fc.Reader.ReadString(byte('\n'))
if err != nil { if err != nil {
fc.Log.Errorf("error reading message: %s", err) fc.Log.Errorf("error reading message from flexradio closing program: %s", err)
continue os.Exit(1)
} }
// regRespSpot := *regexp.MustCompile(`R(\d+)\|0\|(\d+)\n`) // msgRaw := strings.TrimSpace(message)
// respSpot := regRespSpot.FindStringSubmatch(message) // fc.Log.Info(msgRaw)
// if len(respSpot) > 0 { // Response when spot is added
// spot, _ := fc.Repo.FindSpotByCommandNumber(respSpot[1]) regRespSpot := *regexp.MustCompile(`R(\d+)\|0\|(\d+)\n`)
// _, err := fc.Repo.UpdateFlexSpotNumberByID(respSpot[2], *spot) respSpot := regRespSpot.FindStringSubmatch(message)
// if err != nil {
// fc.Log.Errorf("could not update flex spot number in database: %s", err)
// }
// }
// regTriggerSpot := *regexp.MustCompile(`.*\|spot\s(\d+)\striggered.*`) if len(respSpot) > 0 {
// respTrigger := regTriggerSpot.FindStringSubmatch(message) spot, _ := fc.Repo.FindSpotByCommandNumber(respSpot[1])
_, err := fc.Repo.UpdateFlexSpotNumberByID(respSpot[2], *spot)
if err != nil {
fc.Log.Errorf("could not update flex spot number in database: %s", err)
}
}
// if len(respTrigger) > 0 { // Response when a spot is clicked
// spot, err := fc.Repo.FindSpotByFlexSpotNumber(respTrigger[1]) regTriggerSpot := *regexp.MustCompile(`.*spot (\d+) triggered.*\n`)
// if err != nil { respTrigger := regTriggerSpot.FindStringSubmatch(message)
// fc.Log.Errorf("could not find spot by flex spot number in database: %s", err)
// }
// msg := fmt.Sprintf(`To ALL de %s <0233z> : Clicked on %s at %s`, Cfg.SQLite.Callsign, spot.DX, spot.FrequencyHz) if len(respTrigger) > 0 {
// if len(fc.TCPServer.Clients) > 0 { spot, err := fc.Repo.FindSpotByFlexSpotNumber(respTrigger[1])
// fc.MsgChan <- msg if err != nil {
// } fc.Log.Errorf("could not find spot by flex spot number in database: %s", err)
}
// } msg := fmt.Sprintf(`To ALL de %s <%s> : Clicked on "%s" at %s`, Cfg.SQLite.Callsign, spot.UTCTime, spot.DX, spot.FrequencyHz)
if len(fc.TCPServer.Clients) > 0 {
fc.MsgChan <- msg
fc.Log.Infof("%s clicked on spot \"%s\" at %s", Cfg.SQLite.Callsign, spot.DX, spot.FrequencyMhz)
}
}
msg := strings.TrimSpace(message) // Status when a spot is deleted
fc.Log.Info(msg) regSpotDeleted := *regexp.MustCompile(`S\d+\|spot (\d+) removed`)
respDelete := regSpotDeleted.FindStringSubmatch(message)
if len(respDelete) > 0 {
fc.Repo.DeleteSpotByFlexSpotNumber(respDelete[1])
fc.Log.Infof("deleted spot %v from database", respDelete[1])
}
} }
} }

195396
flexradio.log

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,6 @@ import (
prefixed "github.com/x-cray/logrus-prefixed-formatter" prefixed "github.com/x-cray/logrus-prefixed-formatter"
) )
var Log *log.Logger
func NewLog() *log.Logger { func NewLog() *log.Logger {
f, err := os.OpenFile("flexradio.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) f, err := os.OpenFile("flexradio.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil { if err != nil {
@ -18,7 +16,7 @@ func NewLog() *log.Logger {
w := io.MultiWriter(os.Stdout, f) w := io.MultiWriter(os.Stdout, f)
Log := &log.Logger{ l := &log.Logger{
Out: w, Out: w,
Level: log.DebugLevel, Level: log.DebugLevel,
Formatter: &prefixed.TextFormatter{ Formatter: &prefixed.TextFormatter{
@ -29,7 +27,9 @@ func NewLog() *log.Logger {
}, },
} }
return Log l.Level = log.DebugLevel
return l
} }
// Info ... // Info ...
@ -47,6 +47,10 @@ func Error(format string, v ...interface{}) {
log.Errorf(format, v...) log.Errorf(format, v...)
} }
func Debug(format string, v ...interface{}) {
log.Debugf(format, v...)
}
var ( var (
// ConfigError ... // ConfigError ...

23
main.go
View File

@ -44,33 +44,18 @@ func main() {
log := logger.NewLog() log := logger.NewLog()
log.Info("config loaded.") log.Info("config loaded.")
log.Infof("Callsign: %s\n", Cfg.SQLite.Callsign) log.Infof("Callsign: %s", Cfg.SQLite.Callsign)
DeleteDatabase("./flex.sqlite", log) DeleteDatabase("./flex.sqlite", log)
repo := NewFlexDXDatabase("flex.sqlite", log) repo := NewFlexDXDatabase("flex.sqlite", log)
// Create TelnetServer
TCPServer := NewTCPServer(Cfg.Telnet.Host, Cfg.Telnet.Port, log) TCPServer := NewTCPServer(Cfg.Telnet.Host, Cfg.Telnet.Port, log)
FlexClient := NewFlexClient(*repo, *TCPServer, log)
TCPClient := NewTCPClient(*Cfg, TCPServer, FlexClient, log)
// Connect to Flex Radio (ip defined in config file)
FlexClient := NewFlexClient(*repo, TCPServer, log)
go FlexClient.StartFlexClient() go FlexClient.StartFlexClient()
go TCPClient.StartClient()
// Connect to DX Cluster
TelnetClient := TelnetClient{
Address: Cfg.Cluster.Server,
Port: Cfg.Cluster.Port,
Login: Cfg.Cluster.Login,
MsgChan: TCPServer.MsgChan,
CmdChan: TCPServer.CmdChan,
SpotChan: FlexClient.SpotChan,
Log: log,
}
go TelnetClient.StartClient()
// Start TelnetServer
go TCPServer.StartServer() go TCPServer.StartServer()
select {} select {}

View File

@ -105,6 +105,7 @@ func ProcessTelnetSpot(re *regexp.Regexp, spotRaw string, SpotChan chan TelnetSp
spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC) spot.DX, spot.Spotter, spot.Frequency, spot.Band, spot.Mode, spot.Comment, spot.Time, spot.DXCC)
} }
// send spot to SpotChan to Flex Client to send the spot to Flex radio
SpotChan <- spot SpotChan <- spot
} }