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" } if (freq>144000000 && freq<145000000) { band = "2m" } if (freq>432000000 && freq<433000000) { band = "70cm" } 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&appcontact=git@ixyd.net" } else { url = "https://retrieve.pskreporter.info/query?senderCallsign=" + station + "&lastseqno=" + fmt.Sprintf("%d",lastseqno) + "&rronly=true&appcontact=git@ixyd.net" } 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) } }