func (c *wwoConfig) Fetch(loc string, numdays int) iface.Data {
	var params []string
	var resp wwoResponse
	var ret iface.Data
	coordChan := make(chan *iface.LatLon)

	if len(c.apiKey) == 0 {
		log.Fatal("No API key specified. Setup instructions are in the README.")
	}
	params = append(params, "key="+c.apiKey)

	if len(loc) > 0 {
		params = append(params, "q="+url.QueryEscape(loc))
	}
	params = append(params, "format=json")
	params = append(params, "num_of_days="+strconv.Itoa(numdays))
	params = append(params, "tp=3")

	go c.getCoordinatesFromAPI(params, coordChan)

	if c.language != "" {
		params = append(params, "lang="+c.language)
	}
	requri := wwoWuri + strings.Join(params, "&")

	res, err := http.Get(requri)
	if err != nil {
		log.Fatal("Unable to get weather data: ", err)
	} else if res.StatusCode != 200 {
		log.Fatal("Unable to get weather data: http status ", res.StatusCode)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	if c.debug {
		log.Println("Weather request:", requri)
		log.Println("Weather response:", string(body))
	}

	if c.language == "" {
		if err = json.Unmarshal(body, &resp); err != nil {
			log.Println(err)
		}
	} else {
		if err = wwoUnmarshalLang(body, &resp, c.language); err != nil {
			log.Println(err)
		}
	}

	if resp.Data.Req == nil || len(resp.Data.Req) < 1 {
		if resp.Data.Err != nil && len(resp.Data.Err) >= 1 {
			log.Fatal(resp.Data.Err[0].Msg)
		}
		log.Fatal("Malformed response.")
	}

	ret.Location = resp.Data.Req[0].Type + ": " + resp.Data.Req[0].Query
	ret.GeoLoc = <-coordChan

	if resp.Data.CurCond != nil && len(resp.Data.CurCond) > 0 {
		ret.Current = wwoParseCond(resp.Data.CurCond[0], time.Now())
	}

	if resp.Data.Days != nil && numdays > 0 {
		for i, day := range resp.Data.Days {
			ret.Forecast = append(ret.Forecast, wwoParseDay(day, i))
		}
	}

	return ret
}
Exemple #2
0
func (c *forecastConfig) Fetch(location string, numdays int) iface.Data {
	var ret iface.Data
	todayChan := make(chan []iface.Cond)

	if len(c.apiKey) == 0 {
		log.Fatal("No forecast.io API key specified.\nYou have to register for one at https://developer.forecast.io/register")
	}
	if matched, err := regexp.MatchString(`^-?[0-9]*(\.[0-9]+)?,-?[0-9]*(\.[0-9]+)?$`, location); !matched || err != nil {
		log.Fatalf("Error: The forecast.io backend only supports latitude,longitude pairs as location.\nInstead of `%s` try `40.748,-73.985` for example to get a forecast for New York", location)
	}

	c.tz = time.Local

	go func() {
		slots, err := c.fetchToday(location)
		if err != nil {
			log.Fatalf("Failed to fetch todays weather data: %v\n", err)
		}
		todayChan <- slots
	}()

	resp, err := c.fetch(fmt.Sprintf(forecastWuri, c.apiKey, location, c.lang))
	if err != nil {
		log.Fatalf("Failed to fetch weather data: %v\n", err)
	}

	if resp.Latitude == nil || resp.Longitude == nil {
		log.Println("nil response for latitude,longitude")
		ret.Location = location
	} else {
		ret.GeoLoc = &iface.LatLon{Latitude: *resp.Latitude, Longitude: *resp.Longitude}
		ret.Location = fmt.Sprintf("%f,%f", *resp.Latitude, *resp.Longitude)
	}

	if ret.Current, err = c.parseCond(resp.Currently); err != nil {
		log.Fatalf("Could not parse current weather condition: %v", err)
	}
	ret.Forecast = c.ParseDaily(resp.Hourly, numdays)

	if numdays >= 1 {
		var tHistory, tFuture = <-todayChan, ret.Forecast[0].Slots
		var tRet []iface.Cond
		h, f := 0, 0

		// merge forecast and history from current day
		for h < len(tHistory) || f < len(tFuture) {
			if f >= len(tFuture) {
				tRet = append(tRet, tHistory[h])
				h++
			} else if h >= len(tHistory) || tHistory[h].Time.After(tFuture[f].Time) {
				tRet = append(tRet, tFuture[f])
				f++
			} else if tHistory[h].Time.Before(tFuture[f].Time) {
				tRet = append(tRet, tHistory[h])
				h++
			} else {
				tRet = append(tRet, tFuture[f])
				h++
				f++
			}
		}
		ret.Forecast[0].Slots = tRet
	}
	return ret
}