update
This commit is contained in:
88
TCPClient.go
88
TCPClient.go
@@ -12,6 +12,8 @@ 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})`)
|
||||||
|
var defaultLoginRe *regexp.Regexp = regexp.MustCompile("[\\w\\d-_]+ login:")
|
||||||
|
var defaultPasswordRe *regexp.Regexp = regexp.MustCompile("Password:")
|
||||||
|
|
||||||
type TCPClient struct {
|
type TCPClient struct {
|
||||||
Login string
|
Login string
|
||||||
@@ -24,7 +26,7 @@ type TCPClient struct {
|
|||||||
Reader *bufio.Reader
|
Reader *bufio.Reader
|
||||||
Writer *bufio.Writer
|
Writer *bufio.Writer
|
||||||
Scanner *bufio.Scanner
|
Scanner *bufio.Scanner
|
||||||
Conn *net.TCPConn
|
Conn net.Conn
|
||||||
TCPServer TCPServer
|
TCPServer TCPServer
|
||||||
MsgChan chan string
|
MsgChan chan string
|
||||||
CmdChan chan string
|
CmdChan chan string
|
||||||
@@ -33,6 +35,8 @@ type TCPClient struct {
|
|||||||
Log *log.Logger
|
Log *log.Logger
|
||||||
Config *Config
|
Config *Config
|
||||||
Countries Countries
|
Countries Countries
|
||||||
|
LoginRe *regexp.Regexp
|
||||||
|
PasswordRe *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTCPClient(TCPServer *TCPServer, Countries Countries) *TCPClient {
|
func NewTCPClient(TCPServer *TCPServer, Countries Countries) *TCPClient {
|
||||||
@@ -58,35 +62,32 @@ func (c *TCPClient) setDefaultParams() {
|
|||||||
c.LogWriter = bufio.NewWriter(os.Stdout)
|
c.LogWriter = bufio.NewWriter(os.Stdout)
|
||||||
}
|
}
|
||||||
c.LoggedIn = false
|
c.LoggedIn = false
|
||||||
|
|
||||||
|
if c.LoginRe == nil {
|
||||||
|
c.LoginRe = defaultLoginRe
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.PasswordRe == nil {
|
||||||
|
c.PasswordRe = defaultPasswordRe
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TCPClient) StartClient() {
|
func (c *TCPClient) StartClient() {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", c.Address+":"+c.Port)
|
|
||||||
if err != nil {
|
|
||||||
Log.Error("Cannot resolve Telnet Client address:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setDefaultParams()
|
c.setDefaultParams()
|
||||||
c.Conn, err = net.DialTCP("tcp", nil, addr)
|
|
||||||
|
c.Conn, err = net.Dial("tcp", c.Address+":"+c.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Error("Cannot connect to Telnet Client:", err)
|
Log.Error("Cannot connect to Telnet Client:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// err = c.Conn.SetKeepAlive(true)
|
|
||||||
// if err != nil {
|
|
||||||
// Log.Error("Error while setting keep alive:", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
c.Reader = bufio.NewReader(c.Conn)
|
c.Reader = bufio.NewReader(c.Conn)
|
||||||
c.Writer = bufio.NewWriter(c.Conn)
|
c.Writer = bufio.NewWriter(c.Conn)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for message := range c.TCPServer.CmdChan {
|
for message := range c.TCPServer.CmdChan {
|
||||||
Log.Infof("Received Command: %s", message)
|
Log.Infof("Received Command: %s", message)
|
||||||
message := message + "\n"
|
c.Write([]byte(message + "\r\n"))
|
||||||
c.WriteString(message)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -133,64 +134,67 @@ func (c *TCPClient) SetFilters() {
|
|||||||
func (c *TCPClient) ReadLine() {
|
func (c *TCPClient) ReadLine() {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
// Need to check data with space first to find login and then use \n
|
// Need to check data with space first to find login and then use \n
|
||||||
if !c.LoggedIn {
|
if !c.LoggedIn {
|
||||||
message, err := c.Reader.ReadString(' ')
|
message, err := c.Reader.ReadBytes(':')
|
||||||
message, _ = strings.CutSuffix(message, "\n")
|
|
||||||
message, _ = strings.CutSuffix(message, "\r")
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Errorf("Error reading message: %s", err)
|
Log.Errorf("Error reading message: %s", err)
|
||||||
c.Conn.Close()
|
c.Conn.Close()
|
||||||
c.StartClient()
|
c.StartClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(message, Cfg.Cluster.LoginPrompt) {
|
// message, _ = strings.CutSuffix(message, "\n")
|
||||||
|
// message, _ = strings.CutSuffix(message, "\r")
|
||||||
|
|
||||||
|
if strings.Contains(string(message), Cfg.Cluster.LoginPrompt) || strings.Contains(string(message), "login:") {
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
Log.Debug("Found login prompt...sending callsign")
|
Log.Debug("Found login prompt...sending callsign")
|
||||||
c.Write([]byte(c.Login + "\r\n"))
|
c.Write([]byte(c.Login + "\n\r"))
|
||||||
c.LoggedIn = true
|
c.LoggedIn = true
|
||||||
c.SetFilters()
|
|
||||||
if Cfg.Cluster.Command != "" {
|
|
||||||
c.WriteString(Cfg.Cluster.Command + "\n\r")
|
|
||||||
}
|
|
||||||
Log.Infof("Connected to DX cluster %s:%s", Cfg.Cluster.Server, Cfg.Cluster.Port)
|
Log.Infof("Connected to DX cluster %s:%s", Cfg.Cluster.Server, Cfg.Cluster.Port)
|
||||||
Log.Info("Start receiving spots")
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.LoggedIn {
|
if c.LoggedIn {
|
||||||
message, err := c.Reader.ReadString('\n')
|
message, err := c.Reader.ReadBytes('\n')
|
||||||
message, _ = strings.CutSuffix(message, "\n")
|
messageString := string(message)
|
||||||
message, _ = strings.CutSuffix(message, "\r")
|
// Log.Println(messageString)
|
||||||
|
|
||||||
if strings.Contains(message, "password") {
|
|
||||||
Log.Debug("Found password prompt...sending password")
|
|
||||||
c.Write([]byte(c.Password + "\r\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if messageString != "" {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Errorf("Error reading message: %s", err)
|
Log.Errorf("Error reading message: %s", err)
|
||||||
c.Conn.Close()
|
c.Conn.Close()
|
||||||
c.StartClient()
|
c.StartClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(message, "Error reading from server: read tcp") {
|
if strings.Contains(messageString, "password") {
|
||||||
|
Log.Debug("Found password prompt...sending password...")
|
||||||
|
c.Write([]byte(c.Password + "\r\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(messageString, "Hello") || strings.Contains(messageString, "Welcome") {
|
||||||
|
go c.SetFilters()
|
||||||
|
if Cfg.Cluster.Command != "" {
|
||||||
|
c.WriteString(Cfg.Cluster.Command + "\n\r")
|
||||||
|
Log.Debugf("Sending Command: %s", Cfg.Cluster.Command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(messageString, "Error reading from server: read tcp") {
|
||||||
Log.Error("Disconnected from Telnet Server, reconnecting")
|
Log.Error("Disconnected from Telnet Server, reconnecting")
|
||||||
c.Close()
|
c.Close()
|
||||||
c.StartClient()
|
c.StartClient()
|
||||||
} else {
|
|
||||||
if c.LoggedIn && strings.Contains(message, "DX") {
|
|
||||||
ProcessTelnetSpot(spotRe, message, c.SpotChanToFlex, c.SpotChanToHTTPServer, c.Countries)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(messageString, "DX") {
|
||||||
|
ProcessTelnetSpot(spotRe, messageString, c.SpotChanToFlex, c.SpotChanToHTTPServer, c.Countries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the spot message to TCP server
|
// Send the spot message to TCP server
|
||||||
c.MsgChan <- message
|
c.MsgChan <- messageString
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ func (s *TCPServer) StartServer() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
s.Conn, err = s.Listener.Accept()
|
s.Conn, err = s.Listener.Accept()
|
||||||
Log.Info("Client connected", s.Conn.RemoteAddr().String())
|
Log.Info("Client connected: ", s.Conn.RemoteAddr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Error("Could not accept connections to telnet server")
|
Log.Error("Could not accept connections to telnet server")
|
||||||
continue
|
continue
|
||||||
|
14
config.yml
14
config.yml
@@ -2,12 +2,12 @@ general:
|
|||||||
delete_log_file_at_start: true
|
delete_log_file_at_start: true
|
||||||
callsign: F4BPO # Log4OM Callsign used to check if you get spotted by someone
|
callsign: F4BPO # Log4OM Callsign used to check if you get spotted by someone
|
||||||
log_to_file: true
|
log_to_file: true
|
||||||
log_level: DEBUG # INFO or DEBUG or WARN
|
log_level: INFO # INFO or DEBUG or WARN
|
||||||
telnetserver: true # not in use for now
|
telnetserver: true # not in use for now
|
||||||
flexradiospot: true # not in use for now
|
flexradiospot: true # not in use for now
|
||||||
database:
|
database:
|
||||||
mysql: true #only one of the two can be true
|
mysql: false #only one of the two can be true
|
||||||
sqlite: false
|
sqlite: true
|
||||||
mysql_db_user: rouggy
|
mysql_db_user: rouggy
|
||||||
mysql_db_password: 89DGgg290379
|
mysql_db_password: 89DGgg290379
|
||||||
mysql_db_name: log_f4bpo
|
mysql_db_name: log_f4bpo
|
||||||
@@ -16,17 +16,17 @@ database:
|
|||||||
sqlite:
|
sqlite:
|
||||||
sqlite_path: 'C:\Perso\Seafile\Radio\Logs\Log4OM\F4BPO.SQLite' # SQLite Db oath of Log4OM
|
sqlite_path: 'C:\Perso\Seafile\Radio\Logs\Log4OM\F4BPO.SQLite' # SQLite Db oath of Log4OM
|
||||||
cluster:
|
cluster:
|
||||||
server: dxc.sm7iun.se # dxc.k0xm.net dxc.sm7iun.se
|
server: cluster.f4bpo.com # dxc.k0xm.net dxc.sm7iun.se
|
||||||
port: 7300
|
port: 7300
|
||||||
login: f4bpo
|
login: f4bpo
|
||||||
password: 89DGgg
|
password: 89DGgg
|
||||||
skimmer: true
|
skimmer: false
|
||||||
ft8: false
|
ft8: false
|
||||||
ft4: false
|
ft4: false
|
||||||
command: "SET/NOFILTER" #"SET/FILTER DOC/PASS EA,OH,G,F,DL,I,SV,9A,SK,S5,LX,OE,HA,CT"
|
command: "SET/FILTER DOC/PASS 1A,3A,4O,9A,9H,C3,CT,CU,DL,E7,EA,EA6,EI,ER,ES,EU,F,G,GD,GI,GJ,GM,GU,GW,HA,HB,HB0,HV,I,IS,IT9,JW,JX,LA,LX,LY,LZ,OE,OH,OH0,OJ0,OK,OM,ON,OY,OZ,PA,S5,SM,SP,SV,SV5,SV9,T7,TA1,TF,TK,UA,UR,YL,YO,YU,Z6,Z3,ZA,ZB" #"SET/FILTER DOC/PASS 1A,3A,4O,9A,9H,C3,CT,CU,DL,E7,EA,EA6,EI,ER,ES,EU,F,G,GD,GI,GJ,GM,GU,GW,HA,HB,HB0,HV,I,IS,IT9,JW,JX,LA,LX,LY,LZ,OE,OH,OH0,OJ0,OK,OM,ON,OY,OZ,PA,S5,SM,SP,SV,SV5,SV9,T7,TA1,TF,TK,UA,UR,YL,YO,YU,Z6,Z3,ZA,ZB"
|
||||||
login_prompt: "login:"
|
login_prompt: "login:"
|
||||||
flex:
|
flex:
|
||||||
discovery: false # Radio must be on same LAN than the program
|
discovery: true # Radio must be on same LAN than the program
|
||||||
ip: 82.67.157.19 # if discovery is true no need to put an IP
|
ip: 82.67.157.19 # if discovery is true no need to put an IP
|
||||||
spot_life: 600 #seconds
|
spot_life: 600 #seconds
|
||||||
telnetserver: # Log4OM must be connected to this server ie: localhost:7301 if on same machine as this program else ip:7301
|
telnetserver: # Log4OM must be connected to this server ie: localhost:7301 if on same machine as this program else ip:7301
|
||||||
|
27
country.xml
27
country.xml
@@ -9921,33 +9921,6 @@
|
|||||||
</CountryPrefix>
|
</CountryPrefix>
|
||||||
</CountryPrefixList>
|
</CountryPrefixList>
|
||||||
</Country>
|
</Country>
|
||||||
<Country>
|
|
||||||
<ArrlPrefix>VS2</ArrlPrefix>
|
|
||||||
<Comment />
|
|
||||||
<Continent>AS</Continent>
|
|
||||||
<CountryName>Malaya</CountryName>
|
|
||||||
<CqZone>28</CqZone>
|
|
||||||
<CqZoneList>
|
|
||||||
<int>28</int>
|
|
||||||
</CqZoneList>
|
|
||||||
<Dxcc>155</Dxcc>
|
|
||||||
<ItuZone>54</ItuZone>
|
|
||||||
<IaruRegion>3</IaruRegion>
|
|
||||||
<ItuZoneList>
|
|
||||||
<int>54</int>
|
|
||||||
</ItuZoneList>
|
|
||||||
<Latitude>1.3</Latitude>
|
|
||||||
<Longitude>103.8</Longitude>
|
|
||||||
<Active>false</Active>
|
|
||||||
<CountryTag />
|
|
||||||
<CountryPrefixList>
|
|
||||||
<CountryPrefix>
|
|
||||||
<PrefixList>^9M2.*|^VS2.*</PrefixList>
|
|
||||||
<StartDate xsi:nil="true" />
|
|
||||||
<EndDate>1963-09-15T23:59:59Z</EndDate>
|
|
||||||
</CountryPrefix>
|
|
||||||
</CountryPrefixList>
|
|
||||||
</Country>
|
|
||||||
<Country>
|
<Country>
|
||||||
<ArrlPrefix>8Q</ArrlPrefix>
|
<ArrlPrefix>8Q</ArrlPrefix>
|
||||||
<Comment />
|
<Comment />
|
||||||
|
@@ -145,9 +145,9 @@ func (r *Log4OMContactsRepository) ListByCountry(countryID string, contactsChan
|
|||||||
func (r *Log4OMContactsRepository) ListByCountryMode(countryID string, mode string, contactsModeChan chan []Contact, wg *sync.WaitGroup) {
|
func (r *Log4OMContactsRepository) ListByCountryMode(countryID string, mode string, contactsModeChan chan []Contact, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if mode == "USB" || mode == "LSB" {
|
if mode == "USB" || mode == "LSB" || mode == "SSB" {
|
||||||
|
|
||||||
rows, err := r.db.Query("SELECT callsign, band, mode, dxcc, stationcallsign, country FROM log WHERE dxcc = ? AND (mode = ? OR mode = ?)", countryID, "USB", "LSB")
|
rows, err := r.db.Query("SELECT callsign, band, mode, dxcc, stationcallsign, country FROM log WHERE dxcc = ? AND (mode = ? OR mode = ? OR mode = ?)", countryID, "USB", "LSB", "SSB")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("could not query database", err)
|
log.Error("could not query database", err)
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,7 @@ type FlexSpot struct {
|
|||||||
NewMode bool
|
NewMode bool
|
||||||
NewSlot bool
|
NewSlot bool
|
||||||
Worked bool
|
Worked bool
|
||||||
|
CountryName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Discovery struct {
|
type Discovery struct {
|
||||||
@@ -167,6 +168,7 @@ func (fc *FlexClient) SendSpottoFlex(spot TelnetSpot) {
|
|||||||
NewMode: spot.NewMode,
|
NewMode: spot.NewMode,
|
||||||
NewSlot: spot.NewSlot,
|
NewSlot: spot.NewSlot,
|
||||||
Worked: spot.CallsignWorked,
|
Worked: spot.CallsignWorked,
|
||||||
|
CountryName: spot.CountryName,
|
||||||
}
|
}
|
||||||
|
|
||||||
flexSpot.Comment = flexSpot.Comment + " [" + flexSpot.Mode + "] [" + flexSpot.SpotterCallsign + "]"
|
flexSpot.Comment = flexSpot.Comment + " [" + flexSpot.Mode + "] [" + flexSpot.SpotterCallsign + "]"
|
||||||
|
@@ -20,7 +20,7 @@ func Gotify(spot FlexSpot) {
|
|||||||
|
|
||||||
if Cfg.Gotify.Enable && !strings.Contains(ExceptionList, spot.DX) {
|
if Cfg.Gotify.Enable && !strings.Contains(ExceptionList, spot.DX) {
|
||||||
|
|
||||||
message := fmt.Sprintf("DX: %s\nFrom: %s\nFreq: %s\nMode: %s\nTime: %v\n", spot.DX, spot.SpotterCallsign, spot.FrequencyMhz, spot.Mode, spot.TimeStamp)
|
message := fmt.Sprintf("DX: %s\nFrom: %s\nFreq: %s\nMode: %s\nCountry: %s\nTime: %s\n", spot.DX, spot.SpotterCallsign, spot.FrequencyMhz, spot.Mode, spot.CountryName, spot.UTCTime)
|
||||||
|
|
||||||
gotifyMsg := GotifyMessage{
|
gotifyMsg := GotifyMessage{
|
||||||
Title: "",
|
Title: "",
|
||||||
|
1
main.go
1
main.go
@@ -54,6 +54,7 @@ func main() {
|
|||||||
|
|
||||||
// Load country.xml to get all the DXCC number
|
// Load country.xml to get all the DXCC number
|
||||||
Countries := LoadCountryFile()
|
Countries := LoadCountryFile()
|
||||||
|
log.Debug("XML Country File has been loaded properly.")
|
||||||
|
|
||||||
// Database to keep track of all spots
|
// Database to keep track of all spots
|
||||||
fRepo := NewFlexDXDatabase("flex.sqlite")
|
fRepo := NewFlexDXDatabase("flex.sqlite")
|
||||||
|
5
spot.go
5
spot.go
@@ -17,6 +17,7 @@ type TelnetSpot struct {
|
|||||||
Band string
|
Band string
|
||||||
Time string
|
Time string
|
||||||
DXCC string
|
DXCC string
|
||||||
|
CountryName string
|
||||||
Comment string
|
Comment string
|
||||||
CommandNumber int
|
CommandNumber int
|
||||||
FlexSpotNumber int
|
FlexSpotNumber int
|
||||||
@@ -43,7 +44,9 @@ func ProcessTelnetSpot(re *regexp.Regexp, spotRaw string, SpotChanToFlex chan Te
|
|||||||
Time: match[6],
|
Time: match[6],
|
||||||
}
|
}
|
||||||
|
|
||||||
spot.DXCC = GetDXCC(spot.DX, Countries)
|
DXCC := GetDXCC(spot.DX, Countries)
|
||||||
|
spot.DXCC = DXCC.DXCC
|
||||||
|
spot.CountryName = DXCC.CountryName
|
||||||
|
|
||||||
if spot.DXCC == "" {
|
if spot.DXCC == "" {
|
||||||
Log.Errorf("Could not identify the DXCC for %s", spot.DX)
|
Log.Errorf("Could not identify the DXCC for %s", spot.DX)
|
||||||
|
6
xml.go
6
xml.go
@@ -75,7 +75,7 @@ func LoadCountryFile() Countries {
|
|||||||
return countries
|
return countries
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDXCC(dxCall string, Countries Countries) string {
|
func GetDXCC(dxCall string, Countries Countries) DXCC {
|
||||||
DXCCList := []DXCC{}
|
DXCCList := []DXCC{}
|
||||||
d := DXCC{}
|
d := DXCC{}
|
||||||
|
|
||||||
@@ -130,10 +130,10 @@ func GetDXCC(dxCall string, Countries Countries) string {
|
|||||||
DXCCMatch = DXCCList[0]
|
DXCCMatch = DXCCList[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return DXCCMatch.DXCC
|
return DXCCMatch
|
||||||
} else {
|
} else {
|
||||||
Log.Errorf("Could not find %s in country list", dxCall)
|
Log.Errorf("Could not find %s in country list", dxCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return DXCC{}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user