You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

234 lines
7.3 KiB

4 years ago
package main
import (
"encoding/xml"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
"time"
"fmt"
"github.com/tzneal/ham-go/dxcc"
"github.com/mmcloughlin/geohash"
"github.com/pd0mz/go-maidenhead"
)
type receptionReports struct {
XMLName xml.Name `xml:"receptionReports"`
ActiveReceivers []activeReceiver `xml:"activeReceiver"`
LastSequenceNumber lastSequenceNumber `xml:"lastSequenceNumber"`
MaxFlowStartSeconds maxFlowStartSeconds `xml:"maxFlowStartSeconds"`
ReceptionReport []receptionReport `xml:"receptionReport"`
SenderSearch senderSearch `xml:"senderSearch"`
ActiveCallSign []activeCallSign `xml:"activeCallsign"`
Lotw lotw `xml:"lotw"`
}
type activeReceiver struct {
XMLName xml.Name `xml:"activeReceiver"`
CallSign string `xml:"callsign,attr"`
Locator string `xml:"locator,attr"`
Frequency string `xml:"frequency,attr"`
Region string `xml:"region,attr"`
Dxcc string `xml:"DXCC,attr"`
DecoderSoftware string `xml:"decoderSoftware,attr"`
AntennaInformation string `xml:"antennaInformation,attr"`
Mode string `xml:"mode,attr"`
}
type lastSequenceNumber struct {
XMLName xml.Name `xml:"lastSequenceNumber"`
Value int64 `xml:"value,attr"`
}
type maxFlowStartSeconds struct {
XMLName xml.Name `xml:"maxFlowStartSeconds"`
Value string `xml:"value,attr"`
}
type receptionReport struct {
XMLName xml.Name `xml:"receptionReport"`
ReceiverCallSign string `xml:"receiverCallsign,attr"`
ReceiverLocator string `xml:"receiverLocator,attr"`
SenderCallSign string `xml:"senderCallsign,attr"`
SenderLocator string `xml:"senderLocator,attr"`
Frequency float64 `xml:"frequency,attr"`
FlowStartSeconds int64 `xml:"flowStartSeconds,attr"`
Mode string `xml:"mode,attr"`
IsSender bool `xml:"isSender,attr"`
ReceiverDxcc string `xml:"receiverDXCC,attr"`
ReceiverDxccCode string `xml:"receiverDXCCCode,attr"`
SenderLotwUpload string `xml:"senderLotwUpload,attr"`
Snr int `xml:"sNR,attr"`
}
type senderSearch struct {
XMLName xml.Name `xml:"senderSearch"`
CallSign string `xml:"callsign,attr"`
RecentFlowStartSeconds string `xml:"recentFlowStartSeconds,attr"`
}
type activeCallSign struct {
XMLName xml.Name `xml:"activeCallsign"`
CallSign string `xml:"callsign"`
Reports int `xml:"reports"`
Dxcc string `xml:"DXCC"`
DxccCode string `xml:"DXCCCode"`
frequency int `xml:"frequency"`
}
type lotw struct {
XMLName xml.Name `xml:"lotw"`
Upload string `xml:"upload,attr"`
CallSign string `xml:"callsign,attr"`
}
type report struct {
CallSign string
Grid string
Signal int
Mode string
Dxcc string
GeoHash string
Continent string
lastReport int64
Band string
CQZone int
ITUZone int
}
func GetBand(freq float64) (string){
band := "unknown"
if (freq>1000000 && freq<2000000) {
band = "160m"
}
if (freq>3000000 && freq<4000000) {
band = "80m"
}
if (freq>5000000 && freq<6000000) {
band = "60m"
}
if (freq>7000000 && freq<8000000) {
band = "40m"
}
if (freq>10000000 && freq<11000000) {
band = "30m"
}
if (freq>14000000 && freq<15000000) {
band = "20m"
}
if (freq>18000000 && freq<19000000) {
band = "17m"
}
if (freq>21000000 && freq<22000000) {
band = "15m"
}
if (freq>24000000 && freq<25000000) {
band = "12m"
}
if (freq>28000000 && freq<30000000) {
band = "10m"
}
return band
}
func handleReport(receiver receptionReport) (report, bool) {
var r report
// var i int64
Ent, found := dxcc.Lookup(receiver.ReceiverCallSign)
if !found {
log.Warnf("erro while lookup up %s",receiver.ReceiverCallSign)
return r ,false
}
p, err:= maidenhead.ParseLocator(receiver.ReceiverLocator)
if err != nil {
log.Error("crazy shit happened while grid parsing..")
log.Error(err)
return r, false
}
r.CallSign = receiver.ReceiverCallSign
r.Grid = receiver.ReceiverLocator
r.Signal = receiver.Snr
r.Mode = receiver.Mode
r.Dxcc = receiver.ReceiverDxcc
r.Continent = Ent.Continent
r.CQZone = Ent.CQZone
r.ITUZone = Ent.ITUZone
r.lastReport = receiver.FlowStartSeconds
r.GeoHash = geohash.Encode(p.Latitude, p.Longitude)
r.Band = GetBand(receiver.Frequency)
// i, err := strconv.ParseInt(receiver.FlowStartSeconds, 10, 64)
// if err != nil {
// log.WithFields(log.Fields{"err":err}).Error("something went wrong while parsing the timestamp: ",)
// return r, false
// }
// r.lastReport = time.Unix(i, 0)
return r, true
}
func fetchReports(reports chan report) {
var lastseqno int64
var url string
lastseqno = 0
for {
if lastseqno == 0 {
url = "https://retrieve.pskreporter.info/query?senderCallsign=" + station + "&rronly=true"
} else {
url = "https://retrieve.pskreporter.info/query?senderCallsign=" + station + "&lastseqno=" + fmt.Sprintf("%d",lastseqno) + "&rronly=true"
}
log.WithFields(log.Fields{"url":url}).Debug("fetching reports")
resp, err := http.Get(url)
defer resp.Body.Close()
if err != nil {
log.Error("well.. shit happened.. 1")
log.Error(err)
log.Info("sleeping for 300 seconds..")
time.Sleep(300 * time.Second)
continue
}
body,err := ioutil.ReadAll(resp.Body)
if err !=nil {
log.Error("well.. shit happened.. 2")
log.Error(err)
log.Info("sleeping for 300 seconds..")
time.Sleep(300 * time.Second)
continue
}
// phrt.With(prometheus.Labels{"code": fmt.Sprintf("%d",resp.StatusCode)}).Inc()
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
log.Info("fetching reports done.")
rr := receptionReports{}
err = xml.Unmarshal(body,&rr)
if err != nil {
log.Error("well.. shit happened.. 3")
log.Error(err)
log.Info("sleeping for 300 seconds..")
time.Sleep(300 * time.Second)
continue
}
for _, receiver := range rr.ReceptionReport {
r, parsed := handleReport(receiver)
if parsed {
reports <- r
}
}
lastseqno = rr.LastSequenceNumber.Value
} else {
log.WithFields(log.Fields{"response":resp.StatusCode,}).Warn("fetching reports was NOT successfully ")
log.Warn(string(body))
}
log.Info("sleeping for 300 seconds..")
time.Sleep(300 * time.Second)
}
}