Last active
July 2, 2019 22:39
-
-
Save rogerwelin/4ec6d4f59390fdc32d67f492e5a9e530 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import ( | |
| "context" | |
| "encoding/json" | |
| "fmt" | |
| "io/ioutil" | |
| "net/http" | |
| "os" | |
| "sync" | |
| "github.com/aws/aws-lambda-go/events" | |
| "github.com/aws/aws-lambda-go/lambda" | |
| "github.com/aws/aws-sdk-go/service/s3" | |
| "github.com/aws/aws-sdk-go/aws" | |
| "github.com/aws/aws-sdk-go/aws/session" | |
| "github.com/aws/aws-sdk-go/service/s3/s3manager" | |
| ) | |
| const apiUrl = "https://www.metaweather.com/api/location/" | |
| var ( | |
| // hardcoded woe IDs | |
| woeIDS = []string{"906057", | |
| "2487956", | |
| "44418", | |
| "638242", | |
| "2295420", | |
| "2151330", | |
| "615702", | |
| "721943", | |
| "727232", | |
| "766273"} | |
| // Capture environment variables so we know the name of the S3 bucket and which region it's stored in | |
| S3Bucket = os.Getenv("S3BUCKET") | |
| S3Region = os.Getenv("REGION") | |
| ) | |
| // remote json model | |
| type rawWeatherData struct { | |
| ConsolidatedWeather []struct { | |
| WeatherStateName string `json:"weather_state_name"` | |
| MinTemp float64 `json:"min_temp"` | |
| MaxTemp float64 `json:"max_temp"` | |
| Humidity int `json:"humidity"` | |
| Predictability int `json:"predictability"` | |
| } `json:"consolidated_weather"` | |
| Title string `json:"title"` | |
| LocationType string `json:"location_type"` | |
| Woeid int `json:"woeid"` | |
| LattLong string `json:"latt_long"` | |
| } | |
| type AggregatedWeather struct { | |
| WeatherItems []WeatherData `json:"weather_items"` | |
| } | |
| // cleaned json model | |
| type WeatherData struct { | |
| Woeid int `json:"woeid"` | |
| WeatherStateName string `json:"weather_state_name"` | |
| MinTemp float64 `json:"min_temp"` | |
| MaxTemp float64 `json:"max_temp"` | |
| Title string `json:"title"` | |
| LattLong string `json:"latt_long"` | |
| } | |
| func returnHighestPredictability(data *rawWeatherData) (WeatherData, error) { | |
| highestPredictability := 0 | |
| var predictabilityIndex int | |
| for i, p := range data.ConsolidatedWeather { | |
| if p.Predictability > highestPredictability { | |
| highestPredictability = p.Predictability | |
| predictabilityIndex = i | |
| } | |
| } | |
| cleanedData := WeatherData{ | |
| Woeid: data.Woeid, | |
| WeatherStateName: data.ConsolidatedWeather[predictabilityIndex].WeatherStateName, | |
| MinTemp: data.ConsolidatedWeather[predictabilityIndex].MinTemp, | |
| MaxTemp: data.ConsolidatedWeather[predictabilityIndex].MaxTemp, | |
| Title: data.Title, | |
| LattLong: data.LattLong, | |
| } | |
| return cleanedData, nil | |
| } | |
| // func that queries the remote weather api | |
| func (ag *AggregatedWeather) fetchApiData(woeID string, wg *sync.WaitGroup, mu *sync.Mutex) { | |
| defer wg.Done() | |
| var weather WeatherData | |
| var data rawWeatherData | |
| response, err := http.Get(apiUrl + woeID) | |
| if err != nil { | |
| return | |
| } | |
| body, err := ioutil.ReadAll(response.Body) | |
| if err != nil { | |
| return | |
| } | |
| defer response.Body.Close() | |
| if err := json.Unmarshal(body, &data); err != nil { | |
| return | |
| } | |
| weather, err = returnHighestPredictability(&data) | |
| if err != nil { | |
| return | |
| } | |
| mu.Lock() | |
| ag.WeatherItems = append(ag.WeatherItems, weather) | |
| mu.Unlock() | |
| } | |
| // func that takes a filename and upoads it to S3 bucket | |
| func uploadToS3(fileName string) error { | |
| sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(S3Region))) | |
| uploader := s3manager.NewUploader(sess) | |
| file, err := os.Open(fileName) | |
| if err != nil { | |
| return err | |
| } | |
| defer file.Close() | |
| // upload json file to S3 bucket | |
| result, err := uploader.Upload(&s3manager.UploadInput{ | |
| Bucket: aws.String(S3Bucket), | |
| Key: aws.String("data.json"), | |
| Body: file, | |
| ACL: aws.String(s3.ObjectCannedACLPublicRead), | |
| }) | |
| if err != nil { | |
| return err | |
| } | |
| fmt.Printf("File uploaded to: %s\n", aws.StringValue(&result.Location)) | |
| return nil | |
| } | |
| func handleRequest(ctx context.Context, cloudWatchEvent events.CloudWatchEvent) error { | |
| var wg sync.WaitGroup | |
| var mu sync.Mutex | |
| ag := AggregatedWeather{} | |
| // concurrently process the woeids | |
| for _, item := range woeIDS { | |
| wg.Add(1) | |
| go ag.fetchApiData(item, &wg, &mu) | |
| } | |
| wg.Wait() | |
| re, err := json.Marshal(ag) | |
| if err != nil { | |
| return err | |
| } | |
| err = ioutil.WriteFile("/tmp/data.json", re, 0644) | |
| if err != nil { | |
| return err | |
| } | |
| err = uploadToS3("/tmp/data.json") | |
| if err != nil { | |
| return err | |
| } | |
| return nil | |
| } | |
| func main() { | |
| lambda.Start(handleRequest) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment