go-flat-finder/internal/flatfinder/chorus.go

291 lines
8.6 KiB
Go
Raw Normal View History

2022-09-13 09:56:18 +00:00
package flatfinder
import (
2022-09-13 10:44:53 +00:00
"encoding/json"
"errors"
2022-09-13 09:56:18 +00:00
"fmt"
"io"
"log"
"net/http"
"net/url"
)
2022-09-13 10:44:53 +00:00
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"`
}
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"`
}
2022-09-13 09:56:18 +00:00
type ChorusAddressLookupResponse struct {
2022-09-13 10:44:53 +00:00
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"
2022-09-13 09:56:18 +00:00
}
2022-09-13 10:44:53 +00:00
// chorusAddressLookup - Try get the AID for the address
func chorusAddressLookup(address string) (string, error) {
2022-09-13 09:56:18 +00:00
lookupURL := fmt.Sprintf(
"https://api.chorus.co.nz/addresslookup/v1/addresses/?fuzzy=true&q=%s",
url.QueryEscape(address),
)
2022-09-13 10:44:53 +00:00
2022-09-13 09:56:18 +00:00
// Build HTTP request
client := http.Client{}
req, err := http.NewRequest("GET", lookupURL, nil)
if err != nil {
2022-09-13 10:44:53 +00:00
return "", err
2022-09-13 09:56:18 +00:00
}
// 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 {
2022-09-13 10:44:53 +00:00
return "", err
2022-09-13 09:56:18 +00:00
}
defer resp.Body.Close()
2022-09-13 10:44:53 +00:00
// They return a 203
2022-09-13 09:56:18 +00:00
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNonAuthoritativeInfo {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
2022-09-13 10:44:53 +00:00
return "", err
2022-09-13 09:56:18 +00:00
}
2022-09-13 10:44:53 +00:00
// 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)
2022-09-13 09:56:18 +00:00
}
2022-09-13 10:44:53 +00:00
return "", errors.New("Invalid response from API: " + resp.Status)
2022-09-13 09:56:18 +00:00
}
2022-09-13 10:44:53 +00:00
// 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", lookupURL, nil)
if err != nil {
return 0, 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")
// Do the request
resp, err := client.Do(req)
if err != nil {
return 0, 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 {
return 0, err
}
// Decode JSON
var chorusResult ChorusUniqueIdResponse
err = json.Unmarshal(bodyBytes, &chorusResult)
if err != nil {
return 0, err
}
return int64(chorusResult.References.Tlc), nil
}
return 0, errors.New("Invalid response from API: " + resp.Status)
2022-09-13 09:56:18 +00:00
}