func quakeProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var q haz.Quake var res *weft.Result if q.PublicID, res = getPublicIDPath(r); !res.Ok { return res } var t time.Time var mt time.Time var err error if err = db.QueryRow(quakeProtoSQL, q.PublicID).Scan(&t, &mt, &q.Depth, &q.Magnitude, &q.Locality, &q.Mmi, &q.Quality, &q.Longitude, &q.Latitude); err != nil { return weft.ServiceUnavailableError(err) } q.Time = &haz.Timestamp{Sec: t.Unix(), Nsec: int64(t.Nanosecond())} q.ModificationTime = &haz.Timestamp{Sec: mt.Unix(), Nsec: int64(mt.Nanosecond())} var by []byte if by, err = proto.Marshal(&q); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) return &weft.StatusOK }
// fetches SC3ML and turns it into a protobuf. func quakeTechnicalProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } by, res := getBytes(s3+strings.TrimPrefix(r.URL.Path, "/quake/technical/")+".xml", "") if !res.Ok { return res } q, err := sc3ml.QuakeTechnical(by) if err != nil { return weft.ServiceUnavailableError(err) } m, err := proto.Marshal(&q) if err != nil { return weft.ServiceUnavailableError(err) } b.Write(m) h.Set("Content-Type", protobuf) return &weft.StatusOK }
func newsProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } res, err := client.Get(newsURL) defer res.Body.Close() if err != nil { return weft.ServiceUnavailableError(err) } body, err := ioutil.ReadAll(res.Body) if err != nil { return weft.ServiceUnavailableError(err) } f, err := unmarshalNews(body) if err != nil { return weft.ServiceUnavailableError(err) } var n haz.News for _, v := range f.Entries { s := haz.Story{ Title: v.Title, Link: v.Link.Href, } t, err := time.Parse(time.RFC3339, v.Published) if err != nil { return weft.ServiceUnavailableError(err) } ts := haz.Timestamp{Sec: t.Unix(), Nsec: int64(t.Nanosecond())} s.Published = &ts n.Stories = append(n.Stories, &s) } var by []byte if by, err = proto.Marshal(&n); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) h.Set("Surrogate-Control", maxAge300) return &weft.StatusOK }
func intensityProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"type"}, []string{"publicID"}); !res.Ok { return res } var ts string var err error if ts, err = getIntensityType(r); err != nil { return weft.BadRequest(err.Error()) } var shaking *haz.Shaking switch ts { case "measured": if shaking, err = intensityMeasuredLatest(); err != nil { return weft.ServiceUnavailableError(err) } case "reported": publicID := r.URL.Query().Get("publicID") switch publicID { case "": end := time.Now().UTC() start := end.Add(-60 * time.Minute) if shaking, err = intensityReported(start, end); err != nil { return weft.ServiceUnavailableError(err) } default: var t time.Time var res *weft.Result if t, res = getQuakeTime(r); !res.Ok { return res } start := t.Add(-1 * time.Minute) end := t.Add(15 * time.Minute) if shaking, err = intensityReported(start, end); err != nil { return weft.ServiceUnavailableError(err) } } } var by []byte if by, err = proto.Marshal(shaking); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) return &weft.StatusOK }
func quakeHistoryProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var publicID string var res *weft.Result if publicID, res = getPublicIDHistoryPath(r); !res.Ok { return res } var rows *sql.Rows var err error if rows, err = db.Query(quakeHistoryProtoSQL, publicID); err != nil { return weft.ServiceUnavailableError(err) } var quakes []*haz.Quake for rows.Next() { var t time.Time var mt time.Time q := haz.Quake{PublicID: publicID} if err = rows.Scan(&t, &mt, &q.Depth, &q.Magnitude, &q.Locality, &q.Mmi, &q.Quality, &q.Longitude, &q.Latitude); err != nil { return weft.ServiceUnavailableError(err) } q.Time = &haz.Timestamp{Sec: t.Unix(), Nsec: int64(t.Nanosecond())} q.ModificationTime = &haz.Timestamp{Sec: mt.Unix(), Nsec: int64(mt.Nanosecond())} quakes = append(quakes, &q) } qs := haz.Quakes{Quakes: quakes} var by []byte if by, err = proto.Marshal(&qs); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) return &weft.StatusOK }
func quakesWWWnz(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } path := r.URL.Path[quakesNZServiceLen:] // ..."3/100.json" tokens := strings.Split(path, "/") if len(tokens) != 2 { return weft.BadRequest("Bad URL path.") } var mmi int var err error var count int if mmi, err = strconv.Atoi(tokens[0]); err != nil { return weft.BadRequest("Bad URL path. Invalid mmi.") } if count, err = strconv.Atoi(tokens[1][:len(tokens[1])-5]); err != nil { // len(".json") return weft.BadRequest("Bad URL path. Invalid count.") } var d string err = db.QueryRow(quakesNZWWWSQL, mmi, count).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", JSON) return &weft.StatusOK }
func intensityMeasuredLatestV1(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"type"}, []string{}); !res.Ok { return res } if r.URL.Query().Get("type") != "measured" { return weft.BadRequest("type must be measured.") } var d string err := db.QueryRow( `SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(s.location)::json as geometry, row_to_json(( select l from ( select mmi ) as l )) as properties from (select location, mmi FROM impact.intensity_measured) as s ) As f ) as fc`).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V1GeoJSON) return &weft.StatusOK }
func volcanoRegionV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var err error var volcanoId string if volcanoId, err = getVolcanoIDRegion(r); err != nil { return weft.BadRequest(err.Error()) } var d string err = db.QueryRow(`SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(r.region)::json as geometry, row_to_json((SELECT l FROM ( SELECT id, title ) as l )) as properties FROM haz.volcano as r where id = $1) as f ) as fc;`, volcanoId).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func quakeV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } if len(r.URL.Query()) != 0 { return weft.BadRequest("incorrect number of query parameters.") } var publicID string var res *weft.Result if publicID, res = getPublicIDPath(r); !res.Ok { return res } var d string err := db.QueryRow(quakeV2SQL, publicID).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func valV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var d string err := db.QueryRow(`SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(v.location)::json as geometry, row_to_json((SELECT l FROM ( SELECT id AS "volcanoID", title AS "volcanoTitle", alert_level as "level", activity, hazards ) as l )) as properties FROM (haz.volcano JOIN haz.volcanic_alert_level using (alert_level)) as v ) As f ) as fc`).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func quakesProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"MMI"}, []string{}); !res.Ok { return res } var mmi int var err error if mmi, err = getMMI(r); err != nil { return weft.BadRequest(err.Error()) } var rows *sql.Rows if rows, err = db.Query(quakesProtoSQL, mmi); err != nil { return weft.ServiceUnavailableError(err) } var quakes haz.Quakes for rows.Next() { var t time.Time var mt time.Time var q haz.Quake if err = rows.Scan(&q.PublicID, &t, &mt, &q.Depth, &q.Magnitude, &q.Locality, &q.Mmi, &q.Quality, &q.Longitude, &q.Latitude); err != nil { return weft.ServiceUnavailableError(err) } q.Time = &haz.Timestamp{Sec: t.Unix(), Nsec: int64(t.Nanosecond())} q.ModificationTime = &haz.Timestamp{Sec: mt.Unix(), Nsec: int64(mt.Nanosecond())} quakes.Quakes = append(quakes.Quakes, &q) } var by []byte if by, err = proto.Marshal(&quakes); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) return &weft.StatusOK }
func fieldLatestGeoJSON(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { var rows *sql.Rows var err error typeID := r.URL.Query().Get("typeID") var d string err = db.QueryRow("select typeID FROM field.type where typeID = $1", typeID).Scan(&d) if err == sql.ErrNoRows { return &weft.NotFound } if err != nil { return weft.ServiceUnavailableError(err) } if rows, err = dbR.Query(` WITH p as (SELECT geom, time, value, lower, upper, deviceid, typeid FROM field.metric_summary JOIN field.device using (devicePK) JOIN field.threshold using (devicePK, typePK) JOIN field.type using (typePK) WHERE typeID = $1) SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features from (SELECT 'Feature' as type, ST_AsGeoJSON(p.geom)::json as geometry, row_to_json( (SELECT l FROM ( SELECT "time", value, lower, upper, deviceid, typeid ) as l ) ) as properties FROM p ) as f ) as fc`, typeID); err != nil { return weft.InternalServerError(err) } defer rows.Close() var gj string if rows.Next() { if err = rows.Scan(&gj); err != nil { return weft.InternalServerError(err) } } rows.Close() b.WriteString(gj) return &weft.StatusOK }
func quakesRegionV1(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"regionID", "regionIntensity", "number", "quality"}, []string{}); !res.Ok { return res } var err error if _, err = getRegionID(r); err != nil { return weft.BadRequest(err.Error()) } if _, err = getQuality(r); err != nil { return weft.BadRequest(err.Error()) } var regionIntensity string if regionIntensity, err = getRegionIntensity(r); err != nil { return weft.BadRequest(err.Error()) } var n int if n, err = getNumberQuakes(r); err != nil { return weft.BadRequest(err.Error()) } var d string err = db.QueryRow( `SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(q.geom)::json as geometry, row_to_json((SELECT l FROM ( SELECT publicid AS "publicID", to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "time", depth, magnitude, locality, intensity, intensity_newzealand as "regionIntensity", quality ) as l )) as properties FROM haz.quakeapi as q where mmid_newzealand >= $1 ORDER BY time DESC limit $2 ) as f ) as fc`, int(msg.IntensityMMI(regionIntensity)), n).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V1GeoJSON) return &weft.StatusOK }
func feltV1(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"publicID"}, []string{}); !res.Ok { return res } var publicID string var res *weft.Result if publicID, res = getPublicID(r); !res.Ok { return res } var rs *http.Response rs, err := client.Get(feltURL + publicID + ".geojson") defer rs.Body.Close() if err != nil { return weft.ServiceUnavailableError(err) } bt, err := ioutil.ReadAll(rs.Body) if err != nil { return weft.ServiceUnavailableError(err) } // Felt returns a 400 when it should probably be a 404. Tapestry quirk? switch { case http.StatusOK == rs.StatusCode: h.Set("Content-Type", V1GeoJSON) b.Write(bt) return &weft.StatusOK case 4 == rs.StatusCode/100: //res := ¬Found //res.msg = string(bt) return &weft.NotFound case 5 == rs.StatusCode/500: return weft.ServiceUnavailableError(errors.New("error proxying felt resports. Shrug.")) } return weft.ServiceUnavailableError(errors.New("unknown response from felt.")) }
func valProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var err error var rows *sql.Rows if rows, err = db.Query(`SELECT id, title, alert_level, activity, hazards, ST_X(location::geometry), ST_Y(location::geometry) FROM haz.volcano JOIN haz.volcanic_alert_level using (alert_level) ORDER BY alert_level DESC, title ASC`); err != nil { return weft.ServiceUnavailableError(err) } var vol haz.Volcanoes for rows.Next() { v := haz.Volcano{Val: &haz.VAL{}} if err = rows.Scan(&v.VolcanoID, &v.Title, &v.Val.Level, &v.Val.Activity, &v.Val.Hazards, &v.Longitude, &v.Latitude); err != nil { return weft.ServiceUnavailableError(err) } vol.Volcanoes = append(vol.Volcanoes, &v) } var by []byte if by, err = proto.Marshal(&vol); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) return &weft.StatusOK }
func quakesWWWfelt(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var d string err := db.QueryRow(quakesNZWWWSQL, feltMmi, defaultRecordCount).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", JSON) return &weft.StatusOK }
func newsV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } j, err := fetchRSS(newsURL) if err != nil { return weft.ServiceUnavailableError(err) } h.Set("Surrogate-Control", maxAge300) h.Set("Content-Type", V2JSON) b.Write(j) return &weft.StatusOK }
func getPublicIDPath(r *http.Request) (string, *weft.Result) { publicID := r.URL.Path[quakeLen:] if !publicIDRe.MatchString(publicID) { return publicID, weft.BadRequest("invalid publicID: " + publicID) } var d string err := db.QueryRow("select publicid FROM haz.quake where publicid = $1", publicID).Scan(&d) if err == sql.ErrNoRows { return publicID, &weft.NotFound } if err != nil { return publicID, weft.ServiceUnavailableError(err) } return publicID, &weft.StatusOK }
func getQuakeTime(r *http.Request) (time.Time, *weft.Result) { publicID := r.URL.Query().Get("publicID") originTime := time.Time{} if !publicIDRe.MatchString(publicID) { return originTime, weft.BadRequest(fmt.Sprintf("invalid publicID " + publicID)) } err := db.QueryRow("select time FROM haz.quake where publicid = $1", publicID).Scan(&originTime) if err == sql.ErrNoRows { return originTime, &weft.NotFound } if err != nil { return originTime, weft.ServiceUnavailableError(err) } return originTime, &weft.StatusOK }
func quakesVolcanoRegionV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var err error var days int = 90 var volcanoId string if volcanoId, err = getVolcanoIDQuake(r); err != nil { return weft.BadRequest(err.Error()) } var d string err = db.QueryRow(`SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, COALESCE(array_to_json(array_agg(f)), '[]') as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(q.geom)::json as geometry, row_to_json((SELECT l FROM ( SELECT publicid AS "publicID", to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "time", depth, magnitude, locality, intensity, intensity_newzealand as "regionIntensity", floor(mmid_newzealand) as "mmi", quality ) as l )) as properties FROM haz.quakeapi as q where st_covers((select region from haz.volcano hv where id = $1 and q.depth < hv.depth and DATE_PART('day', now() - q.time) < $2), q.geom) ORDER BY time DESC ) as f ) as fc;`, volcanoId, days).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func quakeStatsV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } if len(r.URL.Query()) != 0 { return weft.BadRequest("incorrect number of query parameters.") } var d string err := db.QueryRow(quakeStatsV2SQL).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Surrogate-Control", maxAge300) h.Set("Content-Type", V2JSON) return &weft.StatusOK }
func quakeWWW(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } publicID := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/quake/services/quake/"), ".json") if publicID == "" { return weft.BadRequest("invalid publicID path: " + r.URL.Path) } var d string err := db.QueryRow(quakeWWWSQL, publicID).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", JSON) return &weft.StatusOK }
func intensityV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"type"}, []string{"publicID"}); !res.Ok { return res } var ts string var err error if ts, err = getIntensityType(r); err != nil { return weft.BadRequest(err.Error()) } var d string switch ts { case "measured": err = db.QueryRow(intensityMeasuredLatestV2SQL).Scan(&d) case "reported": publicID := r.URL.Query().Get("publicID") switch publicID { case "": err = db.QueryRow(intenstityReportedLatestV2SQL).Scan(&d) default: var t time.Time var res *weft.Result if t, res = getQuakeTime(r); !res.Ok { return res } err = db.QueryRow(intenstityReportedWindowV2SQL, t.Add(time.Duration(-1*time.Minute)), t.Add(time.Duration(15*time.Minute))).Scan(&d) } } if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func quakeV1(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var publicID string var res *weft.Result if publicID, res = getPublicIDPath(r); !res.Ok { return res } var d string err := db.QueryRow( `SELECT row_to_json(fc) FROM ( SELECT 'FeatureCollection' as type, array_to_json(array_agg(f)) as features FROM (SELECT 'Feature' as type, ST_AsGeoJSON(q.geom)::json as geometry, row_to_json((SELECT l FROM ( SELECT publicid AS "publicID", to_char(time, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') as "time", depth, magnitude, locality, intensity, intensity_newzealand as "regionIntensity", quality ) as l )) as properties FROM haz.quake as q where publicid = $1 ) As f ) as fc`, publicID).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V1GeoJSON) return &weft.StatusOK }
func quakesV2(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{"MMI"}, []string{}); !res.Ok { return res } var mmi int var err error if mmi, err = getMMI(r); err != nil { return weft.BadRequest(err.Error()) } var d string err = db.QueryRow(quakesV2SQL, mmi).Scan(&d) if err != nil { return weft.ServiceUnavailableError(err) } b.WriteString(d) h.Set("Content-Type", V2GeoJSON) return &weft.StatusOK }
func quakeInVolcanoRegionStatsProto(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } var q haz.QuakeStats var rows *sql.Rows var err error var volcanoId string if volcanoId, err = getVolcanoRegionStats(r); err != nil { return weft.BadRequest(err.Error()) } if rows, err = db.Query(fmt.Sprintf(quakesPerDayInVolcanoRegionSQL, 90), volcanoId); err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() for rows.Next() { var t time.Time var r haz.Rate if err = rows.Scan(&t, &r.Count); err != nil { return weft.ServiceUnavailableError(err) } r.Time = &haz.Timestamp{Sec: t.Unix(), Nsec: int64(t.Nanosecond())} q.PerDay = append(q.PerDay, &r) } rows.Close() q.Year = make(map[int32]int32) if rows, err = db.Query(fmt.Sprintf(sumMagsInVolcanoRegionSQL, 365), volcanoId); err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() for rows.Next() { var k, v int32 if err = rows.Scan(&k, &v); err != nil { return weft.ServiceUnavailableError(err) } q.Year[k] = v } rows.Close() q.Month = make(map[int32]int32) if rows, err = db.Query(fmt.Sprintf(sumMagsInVolcanoRegionSQL, 28), volcanoId); err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() for rows.Next() { var k, v int32 if err = rows.Scan(&k, &v); err != nil { return weft.ServiceUnavailableError(err) } q.Month[k] = v } rows.Close() q.Week = make(map[int32]int32) if rows, err = db.Query(fmt.Sprintf(sumMagsInVolcanoRegionSQL, 7), volcanoId); err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() for rows.Next() { var k, v int32 if err = rows.Scan(&k, &v); err != nil { return weft.ServiceUnavailableError(err) } q.Week[k] = v } rows.Close() var by []byte if by, err = proto.Marshal(&q); err != nil { return weft.ServiceUnavailableError(err) } b.Write(by) h.Set("Content-Type", protobuf) h.Set("Surrogate-Control", maxAge300) return &weft.StatusOK }
func capQuakeFeed(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } // we are only serving /cap/1.2/GPAv1.0/feed/atom1.0/quake at the moment and the router // matches that so no need for any further validation here yet. atom := capAtomFeed{ Title: `CAP quakes`, ID: fmt.Sprintf("https://%s/cap/1.2/GPA1.0/feed/atom1.0/quake", serverCName), Link: fmt.Sprintf("https://%s/cap/1.2/GPA1.0/feed/atom1.0/quake", serverCName), } rows, err := db.Query(capQuakeFeedSQL, int(minMMID)) if err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() tLatest := time.Time{} for rows.Next() { var p string var i int t := time.Time{} err := rows.Scan(&p, &i, &t) if err != nil { return weft.ServiceUnavailableError(err) } entry := capAtomEntry{ ID: fmt.Sprintf("http://geonet.org/nz/quakes/%s.%d", p, i), Title: fmt.Sprintf("Quake CAP Message %s.%d", p, i), Updated: t, Summary: fmt.Sprintf("Quake CAP Message %s.%d", p, i), HrefCAP: fmt.Sprintf("https://%s/cap/1.2/GPA1.0/quake/%s.%d", serverCName, p, i), HrefHTML: fmt.Sprintf("http://geonet.org.nz/quakes/%s", p), } atom.Entries = append(atom.Entries, entry) if t.After(tLatest) { tLatest = t } } rows.Close() if tLatest.Equal(time.Time{}) { tLatest = time.Now().UTC() } atom.Updated = tLatest err = capTemplates.ExecuteTemplate(b, "capAtom", atom) if err != nil { return weft.ServiceUnavailableError(err) } h.Set("Content-Type", Atom) return &weft.StatusOK }
func capQuake(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result { if res := weft.CheckQuery(r, []string{}, []string{}); !res.Ok { return res } id := r.URL.Path[22:] if !capIDRe.MatchString(id) { return weft.BadRequest("invalid ID: " + id) } p := strings.Split(id, `.`) if len(p) != 2 { return weft.BadRequest("invalid ID: " + id) } c := capQuakeT{ID: id} c.Quake.PublicID = p[0] rows, err := db.Query(`select modificationTimeUnixMicro, modificationtime from haz.quakehistory where publicid = $1 AND modificationTimeUnixMicro < $2 AND status in ('reviewed','deleted')`, p[0], p[1]) if err != nil { return weft.ServiceUnavailableError(err) } defer rows.Close() c.References = make([]string, 0) for rows.Next() { var i int var t time.Time err := rows.Scan(&i, &t) if err != nil { return weft.ServiceUnavailableError(err) } c.References = append(c.References, fmt.Sprintf("%s.%d,%s", c.Quake.PublicID, i, t.In(nz).Format(time.RFC3339))) } rows.Close() err = db.QueryRow(`select depth, magnitude, status, usedPhaseCount, magnitudestationcount, longitude, latitude, time, modificationTime, intensity FROM haz.quakehistory where publicid = $1 AND modificationTimeUnixMicro = $2`, p[0], p[1]).Scan( &c.Quake.Depth, &c.Quake.Magnitude, &c.Status, &c.Quake.UsedPhaseCount, &c.Quake.MagnitudeStationCount, &c.Quake.Longitude, &c.Quake.Latitude, &c.Quake.Time, &c.Quake.ModificationTime, &c.Intensity, ) if err == sql.ErrNoRows { return &weft.NotFound } if err != nil { return weft.ServiceUnavailableError(err) } cl, err := c.Quake.Closest() if err != nil { return weft.ServiceUnavailableError(err) } c.Localities = c.Quake.Localities(minMMID) if len(c.Localities) == 0 { c.Localities = append(c.Localities, cl) } c.Closest = cl err = capTemplates.ExecuteTemplate(b, "capQuake", c) if err != nil { return weft.ServiceUnavailableError(err) } h.Set("Content-Type", CAP) return &weft.StatusOK }