refactor
This commit is contained in:
+102
-91
@@ -1,5 +1,5 @@
|
||||
use anyhow::Error;
|
||||
use gpui::{Context, Subscription, Task};
|
||||
use gpui::{AppContext, Context, Subscription, Task};
|
||||
use nostr_sdk::prelude::*;
|
||||
use signed_core::{Announcement, RepoAddr, RepoStatus, filters};
|
||||
|
||||
@@ -33,20 +33,16 @@ impl RepoStore {
|
||||
let subscription = cx.subscribe(&backend, |this, _backend, event, cx| {
|
||||
let relevant = match event {
|
||||
BackendEvent::NostrUpdate(update) => {
|
||||
let coordinate = update.coordinate.as_ref() == Some(&this.addr.coordinate());
|
||||
let author = update.author == this.addr.owner;
|
||||
let coordinate = update.coordinate.as_ref() == Some(&this.addr);
|
||||
let author = update.author == this.addr.public_key;
|
||||
let kind = update.kind == Kind::GitRepoAnnouncement;
|
||||
|
||||
coordinate || (author && kind)
|
||||
}
|
||||
BackendEvent::Published(event) => {
|
||||
let kind = event.kind == Kind::GitRepoAnnouncement;
|
||||
let author = event.pubkey == this.addr.owner;
|
||||
let coordinate = event
|
||||
.tags
|
||||
.coordinates()
|
||||
.into_iter()
|
||||
.any(|c| c == this.addr.coordinate());
|
||||
let author = event.pubkey == this.addr.public_key;
|
||||
let coordinate = event.tags.coordinates().into_iter().any(|c| c == this.addr);
|
||||
|
||||
coordinate || (kind && author)
|
||||
}
|
||||
@@ -103,7 +99,8 @@ impl RepoStore {
|
||||
/// Re-query the local database and update all fields.
|
||||
///
|
||||
/// Debounced: concurrent requests are coalesced into a single re-query
|
||||
/// after the running one finishes.
|
||||
/// after the running one finishes. The query and processing run on a
|
||||
/// background thread; only the results are applied on the main thread.
|
||||
pub fn refresh(&mut self, cx: &mut Context<Self>) {
|
||||
if self.refreshing {
|
||||
self.refresh_dirty = true;
|
||||
@@ -114,84 +111,99 @@ impl RepoStore {
|
||||
let client = Backend::global(cx).read(cx).client();
|
||||
let addr = self.addr.clone();
|
||||
|
||||
let task = cx.spawn(async move |this, cx| {
|
||||
loop {
|
||||
let queries = async {
|
||||
let db = client.database();
|
||||
let work = cx.background_spawn(async move {
|
||||
let queries = async {
|
||||
let db = client.database();
|
||||
|
||||
let announcements = db.query(filters::announcement(&addr)).await?;
|
||||
let states = db.query(filters::state(&addr)).await?;
|
||||
let activity = db.query(filters::activity(&addr)).await?;
|
||||
let announcements = db.query(filters::announcement(&addr)).await?;
|
||||
let states = db.query(filters::state(&addr)).await?;
|
||||
let activity = db.query(filters::activity(&addr)).await?;
|
||||
|
||||
Ok::<_, Error>((announcements, states, activity))
|
||||
}
|
||||
.await;
|
||||
Ok::<_, Error>((announcements, states, activity))
|
||||
}
|
||||
.await?;
|
||||
|
||||
let (announcements, states, activity) = match queries {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
return this.update(cx, |this, cx| {
|
||||
this.refreshing = false;
|
||||
this.last_error = Some(e.to_string());
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
};
|
||||
let (announcements, states, activity) = queries;
|
||||
|
||||
let again = this.update(cx, |this, cx| {
|
||||
this.announcement = latest(announcements)
|
||||
.as_ref()
|
||||
.and_then(Announcement::from_event);
|
||||
// Parse and sort off the main thread; only plain data
|
||||
// crosses back into the entity.
|
||||
let announcement = latest(announcements)
|
||||
.as_ref()
|
||||
.and_then(Announcement::from_event);
|
||||
|
||||
if let Some(state) = latest(states) {
|
||||
let (refs, head) = parse_state(&state);
|
||||
this.refs = refs;
|
||||
this.head = head;
|
||||
}
|
||||
let state = latest(states).map(|state| parse_state(&state));
|
||||
|
||||
this.issues.clear();
|
||||
this.patches.clear();
|
||||
this.pull_requests.clear();
|
||||
this.statuses.clear();
|
||||
let (mut issues, mut patches, mut pull_requests, mut statuses) =
|
||||
(Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
||||
|
||||
for event in activity {
|
||||
match event.kind {
|
||||
Kind::GitIssue => this.issues.push(event),
|
||||
Kind::GitPatch => this.patches.push(event),
|
||||
Kind::GitPullRequest | Kind::GitPullRequestUpdate => {
|
||||
this.pull_requests.push(event)
|
||||
}
|
||||
kind if RepoStatus::from_kind(kind).is_some() => {
|
||||
this.statuses.push(event)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
sort_newest_first(&mut this.issues);
|
||||
sort_newest_first(&mut this.patches);
|
||||
sort_newest_first(&mut this.pull_requests);
|
||||
|
||||
cx.notify();
|
||||
|
||||
if this.refresh_dirty {
|
||||
this.refresh_dirty = false;
|
||||
true
|
||||
} else {
|
||||
this.refreshing = false;
|
||||
false
|
||||
}
|
||||
})?;
|
||||
|
||||
if !again {
|
||||
break;
|
||||
for event in activity {
|
||||
match event.kind {
|
||||
Kind::GitIssue => issues.push(event),
|
||||
Kind::GitPatch => patches.push(event),
|
||||
Kind::GitPullRequest | Kind::GitPullRequestUpdate => pull_requests.push(event),
|
||||
kind if RepoStatus::from_kind(kind).is_some() => statuses.push(event),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
sort_newest_first(&mut issues);
|
||||
sort_newest_first(&mut patches);
|
||||
sort_newest_first(&mut pull_requests);
|
||||
|
||||
Ok::<_, Error>((
|
||||
announcement,
|
||||
state,
|
||||
issues,
|
||||
patches,
|
||||
pull_requests,
|
||||
statuses,
|
||||
))
|
||||
});
|
||||
|
||||
self.tasks.push(task);
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
let (announcement, state, issues, patches, pull_requests, statuses) = match work.await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
return this.update(cx, |this, cx| {
|
||||
this.refreshing = false;
|
||||
this.last_error = Some(e.to_string());
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let again = this.update(cx, |this, cx| {
|
||||
this.announcement = announcement;
|
||||
|
||||
if let Some((refs, head)) = state {
|
||||
this.refs = refs;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
this.issues = issues;
|
||||
this.patches = patches;
|
||||
this.pull_requests = pull_requests;
|
||||
this.statuses = statuses;
|
||||
|
||||
cx.notify();
|
||||
|
||||
this.refreshing = false;
|
||||
if this.refresh_dirty {
|
||||
this.refresh_dirty = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})?;
|
||||
|
||||
// Requests that arrived while the refresh was running are
|
||||
// coalesced into one follow-up refresh.
|
||||
if again {
|
||||
this.update(cx, |this, cx| this.refresh(cx))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Resolve the status of a root event (issue / patch / PR) per NIP-34.
|
||||
@@ -213,7 +225,7 @@ impl RepoStore {
|
||||
/// Open an issue on this repository.
|
||||
pub fn open_issue(&mut self, subject: Option<String>, content: String, cx: &mut Context<Self>) {
|
||||
let builder = GitIssue {
|
||||
repository: self.addr.coordinate(),
|
||||
repository: self.addr.clone(),
|
||||
content,
|
||||
subject,
|
||||
labels: Vec::new(),
|
||||
@@ -230,8 +242,8 @@ impl RepoStore {
|
||||
};
|
||||
|
||||
let builder = EventBuilder::new(Kind::GitPatch, patch).tags([
|
||||
Tag::coordinate(self.addr.coordinate(), None),
|
||||
Tag::public_key(self.addr.owner),
|
||||
Tag::coordinate(self.addr.clone(), None),
|
||||
Tag::public_key(self.addr.public_key),
|
||||
root_marker,
|
||||
]);
|
||||
|
||||
@@ -246,9 +258,9 @@ impl RepoStore {
|
||||
|
||||
let builder = EventBuilder::new(status.kind(), "").tags([
|
||||
root_ref,
|
||||
Tag::public_key(self.addr.owner),
|
||||
Tag::public_key(self.addr.public_key),
|
||||
Tag::public_key(root.pubkey),
|
||||
Tag::coordinate(self.addr.coordinate(), None),
|
||||
Tag::coordinate(self.addr.clone(), None),
|
||||
]);
|
||||
|
||||
self.send(builder, cx);
|
||||
@@ -288,16 +300,15 @@ fn parse_state(event: &Event) -> (Vec<(String, String)>, Option<String>) {
|
||||
let mut head = None;
|
||||
|
||||
for tag in event.tags.iter() {
|
||||
let kind = tag.kind();
|
||||
if kind == "HEAD" {
|
||||
head = tag
|
||||
.content()
|
||||
.and_then(|v| v.strip_prefix("ref: refs/heads/"))
|
||||
.map(str::to_owned);
|
||||
} else if kind.starts_with("refs/")
|
||||
&& let Some(commit) = tag.content()
|
||||
{
|
||||
refs.push((kind.to_owned(), commit.to_owned()));
|
||||
match Nip34Tag::parse(tag.as_slice()) {
|
||||
Ok(Nip34Tag::Head(branch)) => head = Some(branch),
|
||||
Ok(Nip34Tag::RefHead { branch, commit }) => {
|
||||
refs.push((format!("refs/heads/{branch}"), commit.to_string()));
|
||||
}
|
||||
Ok(Nip34Tag::RefTag { name, commit }) => {
|
||||
refs.push((format!("refs/tags/{name}"), commit.to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user