func RestoreContactsTable(input *db.RecordReader, output *db.ContactDB) 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 } c := &pb.Contact{} err = proto.Unmarshal(rec, c) if err != nil { log.Printf("Error parsing record: %s", err.Error()) return err } err = output.Store(c) if err != nil { log.Printf("Error writing record: %s", err.Error()) return err } fmt.Printf(".") } fmt.Printf("\n") log.Printf("Contacts table restored.") return nil }
// Consider moving this to a completely different worker binary. func processNewIQData(contact_id string, contactdb *db.ContactDB) { log.Printf("%s: Processing IQ data", contact_id) contact, err := contactdb.Lookup(contact_id) if err != nil { log.Printf("%s: Error looking up contact: %s", contact_id, err.Error()) return } if contact == nil { log.Printf("%s: Contact not found.", contact_id) return } // Get IQParams from the contact. var iq_params *pb.IQParams for _, b := range contact.Blob { if b.Format != nil && *b.Format == pb.Contact_Blob_IQ { if b.IqParams != nil { iq_params = b.IqParams } } } if iq_params == nil { log.Printf("%s: IQ blob missing", contact_id) return } local_path := fmt.Sprintf("%s/%s", *stream_tmp_dir, contact_id) png_path := fmt.Sprintf("%s.png", local_path) demod.Spectrogram(local_path, *iq_params, png_path, demod.SpectrogramTitle(*contact, *iq_params)) if contact.SatelliteId != nil { blobs := processIQDataForSatellite( *contact.SatelliteId, local_path, *iq_params, *contact.StartTimestamp) contact.Blob = append(contact.Blob, blobs...) } log.Printf("%s: Storing updated contact: %v", contact_id, contact.Blob) // TODO: Need to be careful about locking the ContactDB record. // Currently we are the only process that modifies an existing ContactDB // record. In the future we may need to be more careful. if err := contactdb.Store(contact); err != nil { log.Printf("%s: Error storing contact: %s", contact_id, err.Error()) return } log.Printf("%s: Wrote updated contact to db.", contact_id) }
func RedecodeContact(contactdb *db.ContactDB, c *pb.Contact) { if c == nil { log.Fatalf("Contact not found") } log.Printf("Original contact:\n%s\n", proto.MarshalTextString(c)) new_blobs := make([]*pb.Contact_Blob, 0) var freeform []byte for _, b := range c.Blob { if b.Format != nil && (*b.Format == pb.Contact_Blob_DATUM || *b.Format == pb.Contact_Blob_FRAME) { // Strip out datums and frames. continue } new_blobs = append(new_blobs, b) if b.Format != nil && *b.Format == pb.Contact_Blob_FREEFORM { if freeform != nil { log.Fatalf("Contact contains multiple FREEFORM blobs.") } freeform = b.InlineData } } if freeform == nil { return } data, frames := telemetry.DecodeFreeform( *c.SatelliteId, freeform, *c.StartTimestamp) for i, _ := range frames { b := new(pb.Contact_Blob) b.Format = pb.Contact_Blob_FRAME.Enum() b.InlineData = frames[i] new_blobs = append(new_blobs, b) } for i, _ := range data { b := new(pb.Contact_Blob) b.Format = pb.Contact_Blob_DATUM.Enum() b.Datum = &data[i] new_blobs = append(new_blobs, b) } c.Blob = new_blobs log.Printf("New contact:\n%s\n", proto.MarshalTextString(c)) err := contactdb.Store(c) if err != nil { log.Fatalf("Error storing contact: %s", err.Error()) } }
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 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 GetStationContext(s *pb.Station, userid string, m *rpc.Client, userdb *db.UserDB, cdb *db.ContactDB) ( sc stationContext) { sc.S = s sc.IsOwner = (userid == *s.Userid) var args mux.StationStatusArgs args.StationId = *s.Id var status mux.StationStatusResult err := m.Call("Coordinator.StationStatus", args, &status) if err != nil { sc.IsOnline = false } else { sc.IsOnline = status.IsConnected } sc.CurrentTime = time.Now().UTC().Format(TimeFormat) passes, _ := scheduler.PassPredictions(s) passViews := make([]predictionView, 0) for _, pass := range passes { var pv predictionView FillPredictionView(pass, &pv) // Don't display different modes of the same satellite. if len(passViews) == 0 || passViews[len(passViews)-1] != pv { passViews = append(passViews, pv) } } sc.NextPasses = passViews sc.Operator = LookupUserView(userdb, *s.Userid) if sc.IsOwner { c, err := cdb.SearchByStationId(*s.Id, 5) if err != nil { log.Printf("SearchByStationId error: %s", err.Error()) // This is not a fatal error. } sc.Contacts = c } return sc }
// 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 func capturePass( contactdb *db.ContactDB, mux_client *rpc.Client, station pb.Station, pass Prediction) error { log_label := *station.Id satellite_id := *pass.Satellite.Id duration := Duration(pass.EndTimestamp - pass.StartTimestamp) freq_hz := (int64)(*pass.CompatibleMode.channel.FrequencyHz) lateness := (float64)(time.Now().Unix()) - pass.StartTimestamp const kMotorProgramResolution = 10 points, err := PassDetails( time.Now(), duration, *station.Lat, *station.Lng, *station.Elevation, *pass.Satellite.Tle, kMotorProgramResolution) if err != nil { log.Printf("%s: Error getting pass details: %s", log_label, err.Error()) return err } motor_program := make([]mux.MotorCoordinate, len(points)) for i, p := range points { motor_program[i].Timestamp = p.Timestamp motor_program[i].AzimuthDegrees = p.AzimuthDegrees motor_program[i].AltitudeDegrees = p.AltitudeDegrees } log.Printf("%s: Starting capture: satellite %s, "+ "duration: %s, freq_hz: %d, lateness: %f [s]", log_label, satellite_id, duration, freq_hz, lateness) log.Printf("%s: motor_program: %v", log_label, motor_program) // FIXME: future: acquire lock log.Printf("%s: 1", log_label) contact, err := contacts.NewContact( &station, *station.Userid, &satellite_id) if err != nil { log.Printf("%s: Error creating contact: %s", log_label, err.Error()) return err } log_label = *station.Id + "/" + *contact.Id log.Printf("%s: Contact id: %s", log_label, *contact.Id) log.Printf("%s: 2", log_label) err = mux.StationReceiverSetFrequency(mux_client, *station.Id, freq_hz) if err != nil { log.Printf("%s: StationReceiverSetFrequency failed: %s", log_label, err.Error()) return err } log.Printf("%s: 3", log_label) err = contactdb.Store(contact) if err != nil { log.Printf("%s: Error storing contact: %s", log_label, err.Error()) return err } log.Printf("%s: 4", log_label) stream_url := GetStreamURL(*contact.Id) err = mux.StationReceiverStart(mux_client, *station.Id, stream_url) if err != nil { log.Printf("%s: StationReceiverStart failed: %s", log_label, err.Error()) //return err } // Stop the TNC in case it's already started. err = mux.StationTNCStop(mux_client, *station.Id) if err != nil { log.Printf("%s: StationTNCStop failed: %s", log_label, err.Error()) } err = mux.StationTNCStart( mux_client, *station.Id, *api_server_address, satellite_id) if err != nil { log.Printf("%s: StationTNCStart failed: %s", log_label, err.Error()) } log.Printf("%s: 5 StationMotorStart len=%d", log_label, len(motor_program)) err = mux.StationMotorStart(mux_client, *station.Id, motor_program) if err != nil { log.Printf("%s: StationMotorStart failed: %s", log_label, err.Error()) } log.Printf("%s: 6", log_label) time.Sleep(duration) log.Printf("%s: 7", log_label) err = mux.StationTNCStop(mux_client, *station.Id) if err != nil { log.Printf("%s: StationTNCStop failed: %s", log_label, err.Error()) } err = mux.StationReceiverStop(mux_client, *station.Id) if err != nil { log.Printf("%s: StationReceiverStop failed: %s", log_label, err.Error()) } err = mux.StationMotorStop(mux_client, *station.Id) if err != nil { log.Printf("%s: StationMotorStop failed: %s", log_label, err.Error()) } // FIXME: send end timestamp and update contact now := time.Now().Unix() contact.EndTimestamp = &now // FIXME: future: release lock return nil }
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 } }