func consolePageHandler(sdb *db.StationDB, contactdb *db.ContactDB, mux *rpc.Client, w http.ResponseWriter, r *http.Request, user userView) { id := r.URL.Query().Get("id") if id == "" { http.Error(w, "'id' param missing", http.StatusBadRequest) return } station, err := sdb.Lookup(id) if err != nil { log.Printf("Error looking up station: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } auth, _ := canOperateStation(sdb, id, user.Id) if !auth { http.Error(w, "Not authorized", http.StatusUnauthorized) return } var cv consoleViewContext cv.S = *station cv.Satellites = fillSatOptions() c := NewRenderContext(user, cv) err = consoleTemplate.Get().ExecuteTemplate( w, "station_console.html", c) if err != nil { log.Printf("Error rendering station console: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func RestoreStationsTable(input *db.RecordReader, output *db.StationDB) error { for { rec, err := input.ReadRecord() if err == io.EOF { break } else if err != nil { log.Printf("Error reading record: %s", err.Error()) return err } s := &pb.Station{} err = proto.Unmarshal(rec, s) if err != nil { log.Printf("Error parsing record: %s", err.Error()) return err } err = output.Store(s) if err != nil { log.Printf("Error writing record: %s", err.Error()) return err } fmt.Printf(".") } fmt.Printf("\n") log.Printf("Stations table restored.") return nil }
func deleteStationHandler(sdb *db.StationDB, w http.ResponseWriter, r *http.Request, user userView) { id := r.URL.Query().Get("id") if id == "" { http.Error(w, "'id' param missing", http.StatusBadRequest) return } s, err := sdb.Lookup(id) if err != nil { log.Printf("Station DB lookup error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } if s == nil || *s.Userid != user.Id { http.NotFound(w, r) return } err = sdb.Delete(id) if err != nil { log.Printf("Station DB delete error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } // Success http.Redirect(w, r, "/home", http.StatusFound) }
func homeHandler(stationdb *db.StationDB, m *rpc.Client, w http.ResponseWriter, r *http.Request, user userView) { log.Printf("userid: %s", user.Id) hc := homeContext{} n, err := stationdb.NumStations() if err != nil { n = -1 } hc.NumStations = n hc.Stations, err = stationdb.UserStations(user.Id) if err != nil { log.Printf("Error getting user stations: %s", err.Error()) // Continue rendering since it's not a critial error. } var args mux.StationCountArgs var count mux.StationCountResult err = m.Call("Coordinator.StationCount", args, &count) if err != nil { count.Count = -1 } hc.NumOnlineStations = count.Count c := NewRenderContext(user, hc) err = homeTemplate.Get().ExecuteTemplate(w, "home.html", c) if err != nil { log.Printf("Error rendering home page: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func stationViewHandler(sdb *db.StationDB, m *rpc.Client, userdb *db.UserDB, contactdb *db.ContactDB, w http.ResponseWriter, r *http.Request, user userView) { id := r.URL.Query().Get("id") if id == "" { http.Error(w, "'id' param missing", http.StatusBadRequest) return } s, err := sdb.Lookup(id) if err != nil { log.Printf("Sation DB lookup error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } if s == nil { http.NotFound(w, r) return } if s.Capabilities == nil { s.Capabilities = &pb.Capabilities{} } sc := GetStationContext(s, user.Id, m, userdb, contactdb) c := NewRenderContext(user, sc) err = stationViewTemplate.Get().ExecuteTemplate(w, "station.html", c) if err != nil { log.Printf("Error rendering station view: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func editStationHandler(sdb *db.StationDB, w http.ResponseWriter, r *http.Request, user userView) { log.Printf("method: %s", r.Method) id := r.URL.Query().Get("id") if id == "" { http.Error(w, "'id' param missing", http.StatusBadRequest) return } s, err := sdb.Lookup(id) if err != nil { log.Printf("Station DB lookup error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } if s == nil || *s.Userid != user.Id { http.NotFound(w, r) return } if s.Capabilities == nil { s.Capabilities = &pb.Capabilities{} } if r.Method == "POST" { editStationPOST(sdb, s, w, r, user) } else { editStationGET(s, w, r, user) } }
func canOperateStation(sdb *db.StationDB, station_id, userid string) ( bool, error) { owner, err := sdb.GetStationUserId(station_id) if err != nil { log.Printf("Error looking up station: %s", err.Error()) return false, err } return owner == userid, nil }
func AuthenticateStation(sdb *db.StationDB, id, secret string) (bool, error) { s, err := sdb.Lookup(id) if err != nil { return false, err } if s == nil { return false, nil } return *s.Id == id && *s.Secret == secret, nil }
func renderUserProfile( cdb *db.ContactDB, stationdb *db.StationDB, w http.ResponseWriter, r *http.Request, user userView, u *pb.User) { // TODO: It would be better if we could restrict to contacts which // have telemetry. contacts, err := cdb.SearchByUserId(*u.Id, 100) if err != nil { log.Printf("cdb.SearchByUserId error: %s", err.Error()) // Continue since this isn't a critical error. } heard_satellite_ids := make(map[string]bool) for _, c := range contacts { if c.SatelliteId == nil { continue } for _, b := range c.Blob { if b.Format != nil && *b.Format == pb.Contact_Blob_DATUM { heard_satellite_ids[*c.SatelliteId] = true break } } } var pv profileView pv.User = u pv.IsOwner = (*u.Id == user.Id) pv.HeardSatellites = make([]*pb.Satellite, 0) for satellite_id, _ := range heard_satellite_ids { pv.HeardSatellites = append(pv.HeardSatellites, db.GlobalSatelliteDB().Map[satellite_id]) } stations, err := stationdb.UserStations(*u.Id) if err != nil { log.Printf("Error getting user stations: %s", err.Error()) // Continue rendering since it's not a critial error. } pv.Stations = make([]*pb.Station, 0) for _, s := range stations { if s.Lat != nil && s.Lng != nil { pv.Stations = append(pv.Stations, s) } } c := NewRenderContext(user, pv) err = userViewTemplate.Get().ExecuteTemplate(w, "user.html", c) if err != nil { log.Printf("Error rendering user view: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func stationKMLHandler(sdb *db.StationDB, w http.ResponseWriter, r *http.Request) { stations, err := sdb.AllStations() if err != nil { log.Printf("Station DB AllStations error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } err = kmlTemplate.ExecuteTemplate(w, "stations.kml", stations) if err != nil { log.Printf("Error rendering station kml map: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func stationContactsHandler( cdb *db.ContactDB, sdb *db.StationDB, w http.ResponseWriter, r *http.Request, user userView) { id := r.URL.Query().Get("id") if id == "" { http.Error(w, "'id' param missing", http.StatusBadRequest) return } s, err := sdb.Lookup(id) if err != nil { log.Printf("Sation DB lookup error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } if s == nil { http.NotFound(w, r) return } if s.Userid == nil || user.Id != *s.Userid { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } contacts, err := cdb.SearchByStationId(id, 100) if err != nil { log.Printf("SearchByStationId error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } var cv contactsView cv.Title = *s.Name cv.C = contacts c := NewRenderContext(user, cv) err = contactsTemplate.Get().ExecuteTemplate(w, "contacts.html", c) if err != nil { log.Printf("Error rendering contacts view: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func addStationHandler(sdb *db.StationDB, w http.ResponseWriter, r *http.Request, user userView) { station, err := db.NewStation(user.Id) if err != nil { log.Printf("Station DB NewStation error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } if err = sdb.Store(station); err != nil { log.Printf("Station DB Store error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } redirect := stationUrl("/station/edit", *station.Id) http.Redirect(w, r, redirect, http.StatusFound) }
// satellite_id can be empty if unknown func StartNewConsoleContact(stationdb *db.StationDB, contactdb *db.ContactDB, station_id, user_id, satellite_id string) ( id string, err error) { station, err := stationdb.Lookup(station_id) if err != nil { return "", err } if station == nil { return "", errors.New( fmt.Sprintf("Unknown station: %s", station_id)) } s, err := NewContact(station, user_id, &satellite_id) if err != nil { return "", err } if err = contactdb.Store(s); err != nil { return "", err } return *s.Id, nil }
func postPacketHandler( sdb *db.StationDB, cdb *db.ContactDB, w http.ResponseWriter, r *http.Request) { data, err := ioutil.ReadAll(r.Body) r.Body.Close() if err != nil { log.Printf("postPacketHandler: Error reading post body: %s", err.Error()) http.Error(w, "Error reading post body", http.StatusInternalServerError) return } var req PostPacketRequest if err := json.Unmarshal(data, &req); err != nil { log.Printf("postPacketHandler: JSON decode error: %s", err.Error()) http.Error(w, "Error decoding JSON data.", http.StatusBadRequest) return } log.Printf("request: %v", req) frame, err := base64.StdEncoding.DecodeString(req.FrameBase64) if err != nil { log.Printf("postPacketHandler: base64 decode error: %s", err.Error()) http.Error(w, "Error decoding base64 frame.", http.StatusBadRequest) return } if req.StationId == "" { http.Error(w, "Missing station_id", http.StatusBadRequest) return } station, err := sdb.Lookup(req.StationId) if err != nil { log.Printf("Error looking up station: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } contact, poperr := contacts.PopulateContact( req.SatelliteId, req.Timestamp, req.Format, frame, "", req.StationSecret, station) if poperr != nil { poperr.HttpError(w) return } log.Printf("Storing contact: %s", contact) err = cdb.Store(contact) if err != nil { log.Printf("Error storing contact: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) // Do we need to set content-length? }
func getLatestIQDataHandler( sdb *db.StationDB, cdb *db.ContactDB, w http.ResponseWriter, r *http.Request) { log.Printf("Request: %s", r.URL.String()) req, err := parseGetLatestIQDataRequest(r.URL.Query()) if err != nil { log.Printf("getLatestIQDataHandler: "+ "parse request error: %s", err.Error()) http.Error(w, "Error parsing request.", http.StatusBadRequest) return } sat := db.GlobalSatelliteDB().Map[req.SatelliteId] if sat == nil { http.Error(w, "Unknown satellite_id.", http.StatusBadRequest) return } station, err := sdb.Lookup(req.StationId) if err != nil { log.Printf("Error looking up station: %s", err.Error()) http.Error(w, "", http.StatusUnauthorized) return } if station == nil { log.Printf("Error looking up station.") http.Error(w, "", http.StatusUnauthorized) return } // Authenticate the station. if station.Secret == nil || *station.Secret != req.StationSecret { log.Printf("Authentication failed.") http.Error(w, "", http.StatusUnauthorized) return } // Make sure that the user is authorized for the satellite. found_good_id := false for _, station_id := range sat.AuthorizedStationId { if station_id == *station.Id { found_good_id = true } } if !found_good_id { log.Printf("Authentication failed.") http.Error(w, "", http.StatusUnauthorized) return } contacts, err := cdb.SearchBySatelliteId(req.SatelliteId, req.Limit) if err != nil { log.Printf("getLatestIQDataHandler: "+ "SearchBySatelliteId error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } packets := make(GetLatestIQDataResponse, 0) for _, c := range contacts { if c.StartTimestamp == nil { continue } timestamp := *c.StartTimestamp for _, b := range c.Blob { if len(packets) >= req.Limit { continue } if b.Format == nil || *b.Format != pb.Contact_Blob_IQ { continue } var p IQLink p.Timestamp = timestamp p.URL = scheduler.GetStreamURL(*c.Id) if b.IqParams != nil { if b.IqParams.Type != nil { p.Type = b.IqParams.Type.String() } if b.IqParams.SampleRate != nil { p.SampleRate = int( *b.IqParams.SampleRate) } } packets = append(packets, p) } } json_body, err := json.Marshal(packets) if err != nil { log.Printf("json Marshal error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) } w.Header().Add("Content-Length", fmt.Sprintf("%d", len(json_body))) w.Header().Add("Content-Type", "application/json") _, err = w.Write(json_body) if err != nil { log.Printf("Error writing response: %s", err.Error()) } }
// blocking // FIXME: handle disconnections func scheduleStation(stationdb *db.StationDB, contactdb *db.ContactDB, mux_client *rpc.Client, station_id string, shutdown_chan chan string) { defer func() { shutdown_chan <- station_id }() log_label := station_id log.Printf("%s: Scheduling starting.", log_label) for { // Lookup the station in the loop since the owner might // edit the parameters. station, err := stationdb.Lookup(station_id) if err != nil { log.Printf("%s: Station lookup error: %s", log_label, err.Error()) continue } if station == nil { log.Printf("%s: Station doesn't exist.", log_label) return } next_pass, err := getNextPass(station) if err != nil { log.Printf("%s: Error getting pass predictions: %s", log_label, err.Error()) } var delay time.Duration if next_pass.Satellite == nil { // No passes coming up soon. Just wait a bit and try // again. log.Printf("%s: no upcoming passes", log_label) delay = maxPredictionDuration } else if station.SchedulerEnabled == nil || *station.SchedulerEnabled == false { //log.Printf("%s: scheduler disabled", station_id) // TODO: We are effectively polling the SchedulerEnabled // bit. We really should instead have the frontend // send a notification to reschedule the station. delay = controlDisabledDuration } else { log.Printf("%s: next pass: %s", log_label, *next_pass.Satellite.Id) delay = timestamp.TimestampFloatToTime( next_pass.StartTimestamp).Sub(time.Now()) } log.Printf("%s: waiting for %s", log_label, delay) // wait {timer, disconnect} // FIXME: handle disconnections during the sleep time.Sleep(delay) if next_pass.Satellite == nil { continue } // Check that station has enabled scheduling. // We have to look up the station again since it might have // changed while we were sleeping. station, err = stationdb.Lookup(station_id) if err != nil { log.Printf("%s: Station lookup error: %s", log_label, err.Error()) continue } if station == nil { log.Printf("%s: Station doesn't exist.", log_label) return } if station.SchedulerEnabled == nil || *station.SchedulerEnabled == false { continue } err = capturePass(contactdb, mux_client, *station, next_pass) if err != nil { // There was an error of some sort. // Wait a bit before trying again. time.Sleep(errorWaitDuration) } } }
func satellitePostContactHandler( sdb *db.StationDB, cdb *db.ContactDB, w http.ResponseWriter, r *http.Request, user userView) { if r.Method != "POST" { http.Redirect(w, r, satelliteListUrl, http.StatusFound) return } if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } log.Printf("satellitePostContactHandler form: %v\n\n", r.Form) satellite_id := r.Form.Get("satellite_id") if satellite_id == "" { http.Error(w, "Missing satellite id", http.StatusBadRequest) return } sat := db.GlobalSatelliteDB().Map[satellite_id] if sat == nil { http.Error(w, "Unknown satellite id", http.StatusBadRequest) return } timestamp, err := strconv.ParseInt(r.Form.Get("timestamp"), 10, 64) if err != nil { http.Error(w, "Can't parse timestamp.", http.StatusBadRequest) return } data := r.Form.Get("data") frame := ([]byte)(data) var station *pb.Station // There are two options: logged-in or anonymous. if user.Id == "" { // Anonymous station = nil } else { // Logged-in user station_id := r.Form.Get("station_id") if station_id == "" { http.Error( w, "Missing station id", http.StatusBadRequest) return } station, err = sdb.Lookup(station_id) if err != nil { log.Printf("Error looking up station: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } } contact, poperr := contacts.PopulateContact( satellite_id, timestamp, "FREEFORM", frame, user.Id, "", station) if poperr != nil { poperr.HttpError(w) return } log.Printf("Contact: %s", contact) err = cdb.Store(contact) if err != nil { log.Printf("Error storing contact: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } var cc contactConfirmContext cc.SatelliteUrl = satelliteViewURL(*sat.Id) cc.SatelliteName = RenderSatelliteName(sat.Name) cc.Data = data if sat.Schema != nil { t := make([]pb.TelemetryDatum, 0) for _, b := range contact.Blob { if b.Format != nil && *b.Format == pb.Contact_Blob_DATUM { t = append(t, *b.Datum) } } cc.Telemetry = fe_telemetry.RenderTelemetry( *sat.Schema, t, "en") } err = contactConfirmTemplate.Get().ExecuteTemplate( w, "contact_confirm.html", NewRenderContext(user, cc)) if err != nil { log.Printf( "Error rendering contact_confirm view: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func satelliteViewHandler( cdb *db.ContactDB, userdb *db.UserDB, stationdb *db.StationDB, commentdb *db.CommentDB, w http.ResponseWriter, r *http.Request, user userView) { if len(r.URL.Path) < len(satelliteURLPrefix) { http.Error(w, "Invalid path", http.StatusBadRequest) return } id := r.URL.Path[len(satelliteURLPrefix):] sat := db.GlobalSatelliteDB().Map[id] if sat == nil { http.NotFound(w, r) return } // TODO: It would be better if we could restrict to contacts which // have telemetry. contacts, err := cdb.SearchBySatelliteId(id, 100) if err != nil { log.Printf("cdb.SearchBySatelliteId error: %s", err.Error()) // Continue since this isn't a critical error. } t := make([]pb.TelemetryDatum, 0) var latest_contact *contactView for _, c := range contacts { for _, b := range c.Blob { if b.Format != nil && *b.Format == pb.Contact_Blob_DATUM { t = append(t, *b.Datum) if latest_contact == nil { latest_contact = fillContactView( *c, userdb) } } } } sv := satelliteViewContext{} sv.S = sat if sat.Schema != nil { t := fe_telemetry.RenderTelemetry(*sat.Schema, t, "en") if len(t) > 0 { sv.TelemetryHead = t[0] } if len(t) > 1 { sv.TelemetryTail = t[1:] } } sv.LatestContact = latest_contact sv.Comments, _ = LoadCommentsByObjectId( satelliteObjectId(id), commentdb, userdb) sv.Stations, err = stationdb.UserStations(user.Id) if err != nil { log.Printf("Error getting user stations: %s", err.Error()) // Continue rendering since it's not a critial error. } c := NewRenderContext(user, &sv) err = satelliteViewTemplate.Get().ExecuteTemplate( w, "satellite.html", c) if err != nil { log.Printf("Error rendering satellite view: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } }
func editStationPOST(sdb *db.StationDB, s *pb.Station, w http.ResponseWriter, r *http.Request, user userView) { if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } log.Print(r.Form) s.Name = proto.String(r.Form.Get("name")) s.Notes = proto.String(r.Form.Get("notes")) setOptionalFloat(r.Form.Get("latitude"), &s.Lat) setOptionalFloat(r.Form.Get("longitude"), &s.Lng) setOptionalFloat(r.Form.Get("elevation"), &s.Elevation) if r.Form["has_vhf"] == nil { s.Capabilities.VhfLimits = nil } else { vhf := &pb.AzElLimits{} s.Capabilities.VhfLimits = vhf setOptionalFloat(r.Form.Get("vhf_min_azimuth"), &vhf.MinAzimuthDegrees) setOptionalFloat(r.Form.Get("vhf_max_azimuth"), &vhf.MaxAzimuthDegrees) setOptionalFloat(r.Form.Get("vhf_min_elevation"), &vhf.MinElevationDegrees) setOptionalFloat(r.Form.Get("vhf_max_elevation"), &vhf.MaxElevationDegrees) } if r.Form["has_uhf"] == nil { s.Capabilities.UhfLimits = nil } else { uhf := &pb.AzElLimits{} s.Capabilities.UhfLimits = uhf setOptionalFloat(r.Form.Get("uhf_min_azimuth"), &uhf.MinAzimuthDegrees) setOptionalFloat(r.Form.Get("uhf_max_azimuth"), &uhf.MaxAzimuthDegrees) setOptionalFloat(r.Form.Get("uhf_min_elevation"), &uhf.MinElevationDegrees) setOptionalFloat(r.Form.Get("uhf_max_elevation"), &uhf.MaxElevationDegrees) } if r.Form["scheduler_enabled"] == nil { s.SchedulerEnabled = nil } else { s.SchedulerEnabled = proto.Bool(true) } err := sdb.Store(s) if err != nil { log.Printf("Station DB store error: %s", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } redirect := stationUrl("/station", *s.Id) http.Redirect(w, r, redirect, http.StatusFound) }