From 283264a261b461e7cf653d37e7edf06dbf89a7e8 Mon Sep 17 00:00:00 2001 From: Gregory Salaun Date: Wed, 29 Nov 2023 11:02:30 +0700 Subject: [PATCH] first commit --- CloudlogUDP.go | 46 ++++++++++++++++++++++++++++++++++++ cloudlog/cloudlog.go | 51 ++++++++++++++++++++++++++++++++++++++++ clublog/clublog.go | 47 +++++++++++++++++++++++++++++++++++++ config/config.go | 49 ++++++++++++++++++++++++++++++++++++++ config/config.yaml | 20 ++++++++++++++++ go.mod | 5 ++++ go.sum | 4 ++++ qrzcom/qrzcom.go | 53 +++++++++++++++++++++++++++++++++++++++++ qso/qso.go | 56 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 331 insertions(+) create mode 100644 CloudlogUDP.go create mode 100644 cloudlog/cloudlog.go create mode 100644 clublog/clublog.go create mode 100644 config/config.go create mode 100644 config/config.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 qrzcom/qrzcom.go create mode 100644 qso/qso.go diff --git a/CloudlogUDP.go b/CloudlogUDP.go new file mode 100644 index 0000000..c0fb527 --- /dev/null +++ b/CloudlogUDP.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "log" + "net" + "strings" + + "git.rouggy.com/CloudlogUDP/cloudlog" + "git.rouggy.com/CloudlogUDP/clublog" + "git.rouggy.com/CloudlogUDP/config" + "git.rouggy.com/CloudlogUDP/qrzcom" + "git.rouggy.com/CloudlogUDP/qso" +) + +func main() { + fmt.Println("Loading config file...") + + cfg := config.NewConfig() + + fmt.Printf("Launching the server on port %v\n", cfg.UDP.Port) + udpServer, err := net.ListenPacket("udp", cfg.UDP.Port) + if err != nil { + log.Fatal(err) + } + defer udpServer.Close() + fmt.Printf("Server listening on port %v for incoming QSO\n", cfg.UDP.Port) + for { + buf := make([]byte, 4096) + _, _, err := udpServer.ReadFrom(buf) + if err != nil { + fmt.Println(err) + continue + } + msg := string(buf[:]) + msgSplit := strings.Split(msg, "<") + + qso := qso.NewQSO() + qso.ExtractQSOData(msgSplit) + + cloudlog.SendCloudlogMsg(qso, cfg) + qrzcom.SendQRZcomlogMsg(qso, cfg) + clublog.SendClublogMsg(qso, cfg) + + } +} diff --git a/cloudlog/cloudlog.go b/cloudlog/cloudlog.go new file mode 100644 index 0000000..1d20ef5 --- /dev/null +++ b/cloudlog/cloudlog.go @@ -0,0 +1,51 @@ +package cloudlog + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + "git.rouggy.com/CloudlogUDP/config" + "git.rouggy.com/CloudlogUDP/qso" +) + +type CloudlogAPIString struct { + Key string `json:"key"` + StationProfileID string `json:"station_profile_id"` + Type string `json:"type"` + QSOData string `json:"string"` +} + +func SendCloudlogMsg(qso qso.QSO, config config.Config) { + QSODataJson := qso.Call + qso.Band + qso.Mode + qso.Freq + qso.QSODate + qso.TimeOn + qso.RSTR + qso.RSTS + qso.GridSquare + + jsonStr := CloudlogAPIString{ + Key: config.CloudLog.API, + StationProfileID: "1", + Type: "adif", + QSOData: QSODataJson, + } + + b, err := json.Marshal(jsonStr) + if err != nil { + fmt.Println("error:", err) + } + + req, err := http.NewRequest("POST", config.CloudLog.QSOUrl, bytes.NewBuffer(b)) + req.Header.Set("X-Custom-Header", "myvalue") + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + // body, _ := io.ReadAll(resp.Body) + // fmt.Println("response Body:", string(body)) + + fmt.Printf("QSO Details:\nCall: %v\nBand: %v\nFreq: %v\n", qso.Call, qso.Band, qso.Freq) + fmt.Println("QSO Uploaded to Cloudlog") +} diff --git a/clublog/clublog.go b/clublog/clublog.go new file mode 100644 index 0000000..5399948 --- /dev/null +++ b/clublog/clublog.go @@ -0,0 +1,47 @@ +package clublog + +import ( + "fmt" + "net/http" + "net/url" + "strings" + + "git.rouggy.com/CloudlogUDP/config" + "git.rouggy.com/CloudlogUDP/qso" +) + +type ClublogAPI struct { + Email string `json:"email"` + Password string `json:"password"` + Callsign string `json:"callsign"` + ADIF string `json:"adif"` + APIKey string `json:"api"` +} + +func SendClublogMsg(qso qso.QSO, config config.Config) { + QSOData := qso.Call + qso.Band + qso.Mode + qso.Freq + qso.QSODate + qso.TimeOn + qso.RSTR + qso.RSTS + qso.GridSquare + "" + + apiUrl := config.Clublog.URL + data := url.Values{} + data.Set("api", config.Clublog.API) + data.Set("email", config.Clublog.EMail) + data.Set("password", config.Clublog.Password) + data.Set("callsign", config.Clublog.Callsign) + data.Set("adif", QSOData) + + u, _ := url.ParseRequestURI(apiUrl) + urlStr := u.String() + + client := &http.Client{} + r, _ := http.NewRequest(http.MethodPost, urlStr, strings.NewReader(data.Encode())) // URL-encoded payload + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, _ := client.Do(r) + + if http.StatusOK == 200 { + fmt.Println("QSO Uploaded to Clublog") + } else { + fmt.Printf("Error uploading QSO to Clublog %v", resp.Status) + } + +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..6d13ae2 --- /dev/null +++ b/config/config.go @@ -0,0 +1,49 @@ +package config + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + + "gopkg.in/yaml.v2" +) + +// Config from YAML +type Config struct { + CloudLog struct { + Server string `yaml:"server"` + QSOUrl string `yaml:"qso_url"` + API string `yaml:"api"` + } `yaml:"cloudlog"` + UDP struct { + Port string `yaml:"port"` + } `yaml:"udp"` + + QRZ struct { + API string `yaml:"api"` + Callsign string `yaml:"callsign"` + } + Clublog struct { + EMail string `yaml:"email"` + Password string `yaml:"password"` + Callsign string `yaml:"callsign"` + API string `yaml:"api"` + URL string `yaml:"url"` + } +} + +func NewConfig() Config { + var c Config + ex, err := os.Executable() + if err != nil { + log.Println(err) + } + configFile := filepath.Dir(ex) + "/config/config.yaml" + yamlFile, err := ioutil.ReadFile(configFile) + err = yaml.Unmarshal([]byte(yamlFile), &c) + if err != nil { + log.Fatalf("error: %v", err) + } + return c +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..f0a8584 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,20 @@ +# Cloudlog Setup +# Generate a Read/Write API Key cloudlog/api/help +cloudlog: + server: "https://log.rouggy.com" + qso_url: "https://log.rouggy.com/index.php/api/qso/" + api: "cl65388812a62d1" + +udp: + port: ":2240" + +qrz: + api: "4AEC-1886-2E4E-C3AF" + callsign: "XV9Q" + +clublog: + email: "legreg002@hotmail.com" + password: "89DGgg290379" + callsign: "XV9Q" + api: "5767f19333363a9ef432ee9cd4141fe76b8adf38" + url: "https://clublog.org/realtime.php" \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..89b3d99 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.rouggy.com/CloudlogUDP + +go 1.21.4 + +require gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dd0bc19 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/qrzcom/qrzcom.go b/qrzcom/qrzcom.go new file mode 100644 index 0000000..3d715cd --- /dev/null +++ b/qrzcom/qrzcom.go @@ -0,0 +1,53 @@ +package qrzcom + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/url" + + "git.rouggy.com/CloudlogUDP/config" + "git.rouggy.com/CloudlogUDP/qso" +) + +type QRZComAPIString struct { + Key string `json:"KEY"` + Action string `json:"ACTION"` + Adif string `json:"ADIF"` +} + +func SendQRZcomlogMsg(qso qso.QSO, config config.Config) { + + QSODataJson := qso.Call + qso.Band + qso.Mode + qso.Freq + qso.QSODate + qso.TimeOn + qso.RSTR + qso.RSTS + qso.StationCallsign + "" + + jsonStr := QRZComAPIString{ + Key: config.QRZ.API, + Action: "INSERT", + Adif: QSODataJson, + } + + b, err := json.Marshal(jsonStr) + if err != nil { + fmt.Println("error:", err) + } + + params := url.Values{} + params.Add("KEY", jsonStr.Key) + params.Add("ACTION", "INSERT") + params.Add("ADIF", jsonStr.Adif) + + urlQRZ := fmt.Sprint("https://logbook.qrz.com/api?" + params.Encode()) + + req, err := http.NewRequest("POST", urlQRZ, bytes.NewBuffer(b)) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + fmt.Println("QSO Uploaded to QRZ.com") + +} diff --git a/qso/qso.go b/qso/qso.go new file mode 100644 index 0000000..d52228a --- /dev/null +++ b/qso/qso.go @@ -0,0 +1,56 @@ +package qso + +import ( + "strings" +) + +type QSO struct { + Call string + Band string + Mode string + Freq string + QSODate string + TimeOn string + RSTR string + RSTS string + Country string + GridSquare string + StationCallsign string +} + +func NewQSO() QSO { + return *&QSO{} +} + +func (q *QSO) ExtractQSOData(msg []string) { + for _, entry := range msg { + entry = strings.Trim(entry, " ") + + switch { + case strings.Contains(entry, "FREQ:"): + q.Freq = "<" + entry + case strings.Contains(entry, "CALL:"): + q.Call = "<" + entry + case strings.Contains(entry, "BAND:"): + q.Band = "<" + entry + case strings.Contains(entry, "MODE:"): + q.Mode = "<" + entry + case strings.Contains(entry, "QSO_DATE:"): + if q.QSODate == "" { + q.QSODate = "<" + entry + } + case strings.Contains(entry, "TIME_ON:"): + q.TimeOn = "<" + entry + case strings.Contains(entry, "RST_RCVD:"): + q.RSTR = "<" + entry + case strings.Contains(entry, "RST_SENT:"): + q.RSTS = "<" + entry + case strings.Contains(entry, "COUNTRY:"): + q.Country = "<" + entry + case strings.Contains(entry, "GRIDSQUARE:"): + q.GridSquare = "<" + entry + case strings.Contains(entry, "STATION_CALLSIGN:"): + q.StationCallsign = "<" + entry + } + } +}