コード例 #1
0
ファイル: dbtool.go プロジェクト: tstranex/carpcomm
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
}
コード例 #2
0
ファイル: queue.go プロジェクト: tstranex/carpcomm
// 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)
}
コード例 #3
0
ファイル: main.go プロジェクト: tstranex/carpcomm
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())
	}
}
コード例 #4
0
ファイル: users.go プロジェクト: tstranex/carpcomm
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
	}
}
コード例 #5
0
ファイル: contacts.go プロジェクト: tstranex/carpcomm
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
	}
}
コード例 #6
0
ファイル: stations.go プロジェクト: tstranex/carpcomm
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
}
コード例 #7
0
ファイル: populate.go プロジェクト: tstranex/carpcomm
// 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
}
コード例 #8
0
ファイル: packets.go プロジェクト: tstranex/carpcomm
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?
}
コード例 #9
0
ファイル: packets.go プロジェクト: tstranex/carpcomm
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())
	}
}
コード例 #10
0
ファイル: scheduler.go プロジェクト: tstranex/carpcomm
// 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
}
コード例 #11
0
ファイル: satellite.go プロジェクト: tstranex/carpcomm
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
	}
}
コード例 #12
0
ファイル: satellite.go プロジェクト: tstranex/carpcomm
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
	}
}