fn plan_incoming_record()

in components/places/src/history_sync/plan.rs [67:178]


fn plan_incoming_record(conn: &PlacesDb, record: HistoryRecord, max_visits: usize) -> IncomingPlan {
    let url = match Url::parse(&record.hist_uri) {
        Ok(u) => u,
        Err(e) => return IncomingPlan::Invalid(e.into()),
    };

    if !record.id.is_valid_for_places() {
        return IncomingPlan::Invalid(InvalidPlaceInfo::InvalidGuid.into());
    }

    match can_add_url(&url) {
        Ok(can) => {
            if !can {
                return IncomingPlan::Skip;
            }
        }
        Err(e) => return IncomingPlan::Failed(e),
    }
    // Let's get what we know about it, if anything - last 20, like desktop?
    let visit_tuple = match fetch_visits(conn, &url, max_visits) {
        Ok(v) => v,
        Err(e) => return IncomingPlan::Failed(e),
    };

    // This all seems more messy than it should be - struggling to find the
    // correct signature for fetch_visits.
    // An improvement might be to do this via a temp table so we can dedupe
    // and apply in one operation rather than the fetch, rust-merge and update
    // we are doing here.
    let (existing_page, existing_visits): (Option<FetchedVisitPage>, Vec<FetchedVisit>) =
        match visit_tuple {
            None => (None, Vec::new()),
            Some((p, v)) => (Some(p), v),
        };

    let guid_changed = match existing_page {
        Some(p) => p.guid != record.id,
        None => false,
    };

    let mut cur_visit_map: HashSet<(VisitType, Timestamp)> =
        HashSet::with_capacity(existing_visits.len());
    for visit in &existing_visits {
        // it should be impossible for us to have invalid visits locally, but...
        let transition = match visit.visit_type {
            Some(t) => t,
            None => continue,
        };
        match clamp_visit_date(visit.visit_date) {
            Ok(date_use) => {
                cur_visit_map.insert((transition, date_use));
            }
            Err(_) => {
                log::warn!("Ignored visit before 1993-01-23");
            }
        }
    }
    // If we already have MAX_RECORDS visits, then we will ignore incoming
    // visits older than that, to avoid adding dupes of earlier visits.
    // (Not really clear why 20 is magic, but what's good enough for desktop
    // is good enough for us at this stage.)
    // We should also consider pushing this deduping down into storage, where
    // it can possibly do a better job directly in SQL or similar.
    let earliest_allowed: SystemTime = if existing_visits.len() == max_visits {
        existing_visits[existing_visits.len() - 1].visit_date.into()
    } else {
        UNIX_EPOCH
    };

    // work out which of the incoming visits we should apply.
    let mut to_apply = Vec::with_capacity(record.visits.len());
    for incoming_visit in record.visits {
        let transition = match VisitType::from_primitive(incoming_visit.transition) {
            Some(v) => v,
            None => continue,
        };
        match clamp_visit_date(incoming_visit.date.into()) {
            Ok(timestamp) => {
                if earliest_allowed > timestamp.into() {
                    continue;
                }
                // If the entry isn't in our map we should add it.
                let key = (transition, timestamp);
                if !cur_visit_map.contains(&key) {
                    to_apply.push(HistoryRecordVisit {
                        date: timestamp.into(),
                        transition: transition as u8,
                        unknown_fields: incoming_visit.unknown_fields,
                    });
                    cur_visit_map.insert(key);
                }
            }
            Err(()) => {
                log::warn!("Ignored visit before 1993-01-23");
            }
        }
    }
    // Now we need to check the other attributes.
    // Check if we should update title? For now, assume yes. It appears
    // as though desktop always updates it.
    if guid_changed || !to_apply.is_empty() {
        let new_title = Some(record.title);
        IncomingPlan::Apply {
            url,
            new_title,
            visits: to_apply,
            unknown_fields: record.unknown_fields,
        }
    } else {
        IncomingPlan::Reconciled
    }
}