Working internet speeds

This commit is contained in:
idanoo 2022-09-13 22:44:53 +12:00
parent 9927075d15
commit a87f8e21fe
Signed by: idanoo
GPG Key ID: 387387CDBC02F132
6 changed files with 259 additions and 70 deletions

13
flatfinder.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=FlatFinder
After=network.target
[Service]
ExecStart=/root/flatfinder
WorkingDirectory=/root
Type=simple
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

4
go.mod
View File

@ -3,7 +3,6 @@ module flatfinder
go 1.19
require (
github.com/bwmarrin/discordgo v0.26.1
github.com/disgoorg/disgo v0.13.19
github.com/disgoorg/snowflake/v2 v2.0.0
github.com/joho/godotenv v1.4.0
@ -11,8 +10,5 @@ require (
require (
github.com/disgoorg/log v1.2.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b // indirect
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
)

13
go.sum
View File

@ -1,5 +1,3 @@
github.com/bwmarrin/discordgo v0.26.1 h1:AIrM+g3cl+iYBr4yBxCBp9tD9jR3K7upEjl0d89FRkE=
github.com/bwmarrin/discordgo v0.26.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/disgoorg/disgo v0.13.19 h1:evbkWRQ9fU3dIrRJnl+jFTt55cKAeeEwnB/Q3dqgz20=
github.com/disgoorg/disgo v0.13.19/go.mod h1:Cyip4bCYHD3rHgDhBPT9cLo81e9AMbDe8ocM50UNRM4=
@ -7,21 +5,10 @@ github.com/disgoorg/log v1.2.0 h1:sqlXnu/ZKAlIlHV9IO+dbMto7/hCQ474vlIdMWk8QKo=
github.com/disgoorg/log v1.2.0/go.mod h1:3x1KDG6DI1CE2pDwi3qlwT3wlXpeHW/5rVay+1qDqOo=
github.com/disgoorg/snowflake/v2 v2.0.0 h1:+xvyyDddXmXLHmiG8SZiQ3sdZdZPbUR22fSHoqwkrOA=
github.com/disgoorg/snowflake/v2 v2.0.0/go.mod h1:SPU9c2CNn5DSyb86QcKtdZgix9osEtKrHLW4rMhfLCs=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b h1:qYTY2tN72LhgDj2rtWG+LI6TXFl2ygFQQ4YezfVaGQE=
github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@ -1,6 +1,8 @@
package flatfinder
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
@ -8,92 +10,281 @@ import (
"net/url"
)
type ChorusAddressLookupResponse struct {
type ChorusAddressSearchResponse struct {
Results []struct {
Aid string `json:"aid"`
Label string `json:"label"`
Links []struct {
Rel string `json:"rel"`
Href string `json:"href"`
Method string `json:"method"`
} `json:"links"`
} `json:"results"`
}
func chorusAddressLookup(address string) string {
log.Printf("Querying address: %s", address)
type ChorusUniqueIdResponse struct {
FormattedAddress struct {
Line1 string `json:"line1"`
Line2 interface{} `json:"line2"`
Line3 string `json:"line3"`
Line4 string `json:"line4"`
} `json:"formattedAddress"`
StructuredAddress struct {
LevelNumber interface{} `json:"levelNumber"`
LevelType interface{} `json:"levelType"`
StreetNumber int `json:"streetNumber"`
SituationNumber int `json:"situationNumber"`
Suffix interface{} `json:"suffix"`
Unit interface{} `json:"unit"`
UnitType interface{} `json:"unitType"`
StreetName string `json:"streetName"`
RoadType string `json:"roadType"`
RoadAbv string `json:"roadAbv"`
RoadSuffix interface{} `json:"roadSuffix"`
Suburb string `json:"suburb"`
RuralDelivery interface{} `json:"ruralDelivery"`
Town string `json:"town"`
Postcode string `json:"postcode"`
BoxNumber interface{} `json:"boxNumber"`
BoxLobby interface{} `json:"boxLobby"`
BoxType interface{} `json:"boxType"`
Region string `json:"region"`
Country string `json:"country"`
IsPrimary string `json:"isPrimary"`
} `json:"structuredAddress"`
Location struct {
NztmX float64 `json:"nztmX"`
NztmY float64 `json:"nztmY"`
NzmgX float64 `json:"nzmgX"`
NzmgY float64 `json:"nzmgY"`
Wgs84Lat float64 `json:"wgs84Lat"`
Wgs84Lon float64 `json:"wgs84Lon"`
} `json:"location"`
References struct {
Aid string `json:"aid"`
Dpid interface{} `json:"dpid"`
Tui int `json:"tui"`
Tlc int `json:"tlc"`
Plsam int `json:"plsam"`
} `json:"references"`
Related []interface{} `json:"related"`
Links []struct {
Rel string `json:"rel"`
Href string `json:"href"`
Method string `json:"method"`
} `json:"links"`
}
type ChorusAddressLookupResponse struct {
RegionRsp string `json:"region_rsp"`
SubregionRsp string `json:"subregion_rsp"`
AreaHyperfibre string `json:"area_hyperfibre"`
AlternativeFibreProvider string `json:"alternative_fibre_provider"`
AreaFibreSupplier string `json:"area_fibre_supplier"`
PointOfInterconnect string `json:"point_of_interconnect"`
ProductZoneType string `json:"product_zone_type"`
ActiveServices []struct {
Service string `json:"service"`
SpeedMbps int `json:"speed_mbps"`
SpeedUlMbps int `json:"speed_ul_mbps"`
} `json:"active_services"`
AvailableServices []struct {
Service string `json:"service"`
ServiceIndicator string `json:"service_indicator"`
Capable string `json:"capable"`
SpeedMbps float64 `json:"speed_mbps"`
InstallLeadTimeDays string `json:"install_lead_time_days,omitempty"`
InstallLeadTimeWeeks string `json:"install_lead_time_weeks,omitempty"`
SpeedUlMbps float64 `json:"speed_ul_mbps,omitempty"`
} `json:"available_services"`
FutureServices []interface{} `json:"future_services"`
Fibre struct {
BuildRequired string `json:"build_required"`
ConsentRequired string `json:"consent_required"`
ConsentStatus string `json:"consent_status"`
DesignRequired string `json:"design_required"`
DwellingType string `json:"dwelling_type"`
FibreInADayCapable string `json:"fibre_in_a_day_capable"`
Greenfields string `json:"greenfields"`
IntactOnt string `json:"intact_ont"`
MduBuildStatus string `json:"mdu_build_status"`
MduClass string `json:"mdu_class"`
MduDesignStatus interface{} `json:"mdu_design_status"`
PermitDelayLikely string `json:"permit_delay_likely"`
RightOfWay string `json:"right_of_way"`
} `json:"fibre"`
Copper struct {
PremiseWiringRecommended string `json:"premise_wiring_recommended"`
} `json:"copper"`
}
// getAvailableSpeeds - Checks if VDSL/FIBRE is available
func getAvailableSpeeds(address string) (string, string) {
aid, err := chorusAddressLookup(address)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
// log.Printf("Using AID: %s", aid)
tlc, err := chorusGetUnqiueID(aid)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
// log.Printf("Using TLC: %d", tlc)
chorusURL := fmt.Sprintf("https://www.chorus.co.nz/api/bbc/bcc/%d", tlc)
client := http.Client{}
req, err := http.NewRequest("GET", chorusURL, nil)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
// Do the request
resp, err := client.Do(req)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
// Decode JSON
var chorusResult ChorusAddressLookupResponse
err = json.Unmarshal(bodyBytes, &chorusResult)
if err != nil {
log.Print(err)
return "UNK", "UNK"
}
hasFibre := "No"
if chorusResult.Fibre.BuildRequired == "N" {
hasFibre = "Yes"
}
maxSpeed := 0.0
for _, available := range chorusResult.AvailableServices {
if available.SpeedMbps > maxSpeed && available.Capable == "YES" {
maxSpeed = available.SpeedMbps
}
}
current := "None"
for _, active := range chorusResult.ActiveServices {
current = fmt.Sprintf("%s (%d Mbps)", active.Service, active.SpeedMbps)
}
return fmt.Sprintf("%s (%.0f Mbps)", hasFibre, maxSpeed), current
} else {
log.Print("Invalid response from API: " + resp.Status)
}
return "UNK", "UNK"
}
// chorusAddressLookup - Try get the AID for the address
func chorusAddressLookup(address string) (string, error) {
lookupURL := fmt.Sprintf(
"https://api.chorus.co.nz/addresslookup/v1/addresses/?fuzzy=true&q=%s",
url.QueryEscape(address),
)
//curl 'https://api.chorus.co.nz/addresslookup/v1/addresses/?fuzzy=true&q=35%20Rosalind' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0' -H 'Accept: application/json, text/plain, */*' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'X-Chorus-Client-Id: 82d4b4a8050c4d5e97c5f06120ef9c04' -H 'X-Chorus-Client-Secret: 8899c64746474Cf18849c6B721b5Db51' -H 'X-Transaction-Id: ca5ef871-9b3f-4af4-958d-ee9c51094e08' -H 'Origin: https://www.chorus.co.nz'
// Build HTTP request
client := http.Client{}
req, err := http.NewRequest("GET", lookupURL, nil)
if err != nil {
log.Print(err)
return "UNK"
return "", err
}
// Magic numbers - May need to dynamically receive these
req.Header.Set("X-Chorus-Client-Id", "82d4b4a8050c4d5e97c5f06120ef9c04")
req.Header.Set("X-Chorus-Client-Secret", "8899c64746474Cf18849c6B721b5Db51")
req.Header.Set("X-Transaction-Id", "ca5ef871-9b3f-4af4-958d-ee9c51094e08")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "https://tinker.nz/idanoo/flat-finder")
// Do the request
resp, err := client.Do(req)
if err != nil {
log.Print(err)
return "UNK"
return "", err
}
defer resp.Body.Close()
// They return a 203
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNonAuthoritativeInfo {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Print(err)
return "UNK"
return "", err
}
log.Println(string(bodyBytes))
return "N/A"
} else {
log.Print("Invalid response from API: " + resp.Status)
// Decode JSON
var chorusResult ChorusAddressSearchResponse
err = json.Unmarshal(bodyBytes, &chorusResult)
if err != nil {
return "", err
}
// If we have a result, return the first one
for _, result := range chorusResult.Results {
return result.Aid, nil
}
return "", errors.New("No results found for address: " + address)
}
return "UNK"
return "", errors.New("Invalid response from API: " + resp.Status)
}
// getAvailableSpeeds - Checks if VDSL/FIBRE is available
func getAvailableSpeeds(address string) string {
return chorusAddressLookup(address)
// chorusGetUniqueID - Return ID needed to get avail services
func chorusGetUnqiueID(aid string) (int64, error) {
lookupURL := fmt.Sprintf(
"https://api.chorus.co.nz/addresslookup/v1/addresses/aid:%s",
aid,
)
// // Build HTTP request
// client := http.Client{}
// req, err := http.NewRequest("GET", chorusURL, nil)
// if err != nil {
// log.Print(err)
// return "UNK"
// }
// Build HTTP request
client := http.Client{}
req, err := http.NewRequest("GET", lookupURL, nil)
if err != nil {
return 0, err
}
// req.Header.Set("Content-TypeContent-Type", "application/json")
// req.Header.Set("User-Agent", "https://tinker.nz/idanoo/flat-finder")
// Magic numbers - May need to dynamically receive these
req.Header.Set("X-Chorus-Client-Id", "82d4b4a8050c4d5e97c5f06120ef9c04")
req.Header.Set("X-Chorus-Client-Secret", "8899c64746474Cf18849c6B721b5Db51")
req.Header.Set("X-Transaction-Id", "ca5ef871-9b3f-4af4-958d-ee9c51094e08")
req.Header.Set("Content-Type", "application/json")
// // Do the request
// resp, err := client.Do(req)
// if err != nil {
// log.Print(err)
// return "UNK"
// }
// defer resp.Body.Close()
// Do the request
resp, err := client.Do(req)
if err != nil {
return 0, err
}
defer resp.Body.Close()
// if resp.StatusCode == http.StatusOK {
// bodyBytes, err := io.ReadAll(resp.Body)
// if err != nil {
// log.Print(err)
// return "UNK"
// }
// They return a 203
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNonAuthoritativeInfo {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return 0, err
}
// log.Println(string(bodyBytes))
// Decode JSON
var chorusResult ChorusUniqueIdResponse
err = json.Unmarshal(bodyBytes, &chorusResult)
if err != nil {
return 0, err
}
// return "N/A"
// } else {
// log.Print("Invalid response from API: " + resp.Status)
// }
return int64(chorusResult.References.Tlc), nil
}
return "UNK"
return 0, errors.New("Invalid response from API: " + resp.Status)
}

View File

@ -37,7 +37,7 @@ func (c *LocalConfig) initDiscord() {
func (c *LocalConfig) sendEmbeddedMessage(listing TradeMeListing) {
log.Printf("New listing: %s", listing.Title)
hasFibre := getAvailableSpeeds(
hasFibre, currentConn := getAvailableSpeeds(
fmt.Sprintf(
"%s, %s, %s",
strings.TrimSpace(listing.Address),
@ -62,7 +62,8 @@ func (c *LocalConfig) sendEmbeddedMessage(listing TradeMeListing) {
true,
).
AddField("Bedrooms", fmt.Sprintf("%d", listing.Bedrooms), true).
AddField("Has Fibre", hasFibre, true)
AddField("Fibre Avail", hasFibre, false).
AddField("Current Connection", currentConn, false)
// Only add address if token set
if c.GoogleApiToken != "" && c.GoogleLocation1 != "" {

View File

@ -34,10 +34,11 @@ func (c *LocalConfig) loadConfig() {
// Load it into global
err = json.Unmarshal(data, c)
if err != nil {
log.Fatal(err)
maps := make(map[int64]bool)
c.PostedProperties = maps
} else {
log.Printf("Loaded %d previously posted property IDs", len(c.PostedProperties))
}
log.Printf("Loaded %d previously posted property IDs", len(c.PostedProperties))
} else {
// Create empty map for first run
maps := make(map[int64]bool)