-
Notifications
You must be signed in to change notification settings - Fork 87
/
Copy pathglobals.rs
218 lines (180 loc) · 7.16 KB
/
globals.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
use crate::comms::{ToMinionMessage, ToOverlordMessage};
use crate::db::DbRelay;
use crate::events::Events;
use crate::feed::Feed;
use crate::fetcher::Fetcher;
use crate::people::People;
use crate::relationship::Relationship;
use crate::settings::Settings;
use crate::signer::Signer;
use nostr_types::{Event, Id, Profile, PublicKeyHex, Url};
use rusqlite::Connection;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, AtomicU32};
use tokio::sync::{broadcast, mpsc, Mutex, RwLock};
/// Only one of these is ever created, via lazy_static!, and represents
/// global state for the rust application
pub struct Globals {
/// This is our connection to SQLite. Only one thread at a time.
pub db: Mutex<Option<Connection>>,
/// This is a broadcast channel. All Minions should listen on it.
/// To create a receiver, just run .subscribe() on it.
pub to_minions: broadcast::Sender<ToMinionMessage>,
/// This is a mpsc channel. The Overlord listens on it.
/// To create a sender, just clone() it.
pub to_overlord: mpsc::UnboundedSender<ToOverlordMessage>,
/// This is ephemeral. It is filled during lazy_static initialization,
/// and stolen away when the Overlord is created.
pub tmp_overlord_receiver: Mutex<Option<mpsc::UnboundedReceiver<ToOverlordMessage>>>,
/// All nostr events currently in memory, keyed by the event Id, as well as
/// information about if they are new or not, and functions
pub events: Events,
/// Events coming in from relays that are not processed yet
/// stored with Url they came from and Subscription they came in on
pub incoming_events: RwLock<Vec<(Event, Url, Option<String>)>>,
/// All relationships between events
pub relationships: RwLock<HashMap<Id, Vec<(Id, Relationship)>>>,
/// All nostr people records currently loaded into memory, keyed by pubkey
pub people: People,
/// All nostr relay records we have
pub relays: RwLock<HashMap<Url, DbRelay>>,
/// The relays we are currently connected to
pub relays_watching: RwLock<Vec<Url>>,
/// Whether or not we are shutting down. For the UI (minions will be signaled and
/// waited for by the overlord)
pub shutting_down: AtomicBool,
/// Settings
pub settings: RwLock<Settings>,
/// Signer
pub signer: RwLock<Signer>,
/// Dismissed Events
pub dismissed: RwLock<Vec<Id>>,
/// Feed
pub feed: Feed,
/// Fetcher
pub fetcher: Fetcher,
/// Failed Avatar Fetches
pub failed_avatars: RwLock<HashSet<PublicKeyHex>>,
pub pixels_per_point_times_100: AtomicU32,
/// UI status message
pub status_message: RwLock<String>,
pub pull_following_merge: AtomicBool,
}
lazy_static! {
pub static ref GLOBALS: Globals = {
// Setup a communications channel from the Overlord to the Minions.
let (to_minions, _) = broadcast::channel(256);
// Setup a communications channel from the Minions to the Overlord.
let (to_overlord, tmp_overlord_receiver) = mpsc::unbounded_channel();
Globals {
db: Mutex::new(None),
to_minions,
to_overlord,
tmp_overlord_receiver: Mutex::new(Some(tmp_overlord_receiver)),
events: Events::new(),
incoming_events: RwLock::new(Vec::new()),
relationships: RwLock::new(HashMap::new()),
people: People::new(),
relays: RwLock::new(HashMap::new()),
relays_watching: RwLock::new(Vec::new()),
shutting_down: AtomicBool::new(false),
settings: RwLock::new(Settings::default()),
signer: RwLock::new(Signer::default()),
dismissed: RwLock::new(Vec::new()),
feed: Feed::new(),
fetcher: Fetcher::new(),
failed_avatars: RwLock::new(HashSet::new()),
pixels_per_point_times_100: AtomicU32::new(139), // 100 dpi, 1/72th inch => 1.38888
status_message: RwLock::new("Welcome to Gossip. Status messages will appear here. Click them to dismiss them.".to_owned()),
pull_following_merge: AtomicBool::new(true),
}
};
}
impl Globals {
/*
pub async fn get_local_event(id: Id) -> Option<Event> {
// Try memory
if let Some(e) = GLOBALS.events.get(&id) {
return Some(e.to_owned())
}
// Try the database
}
*/
pub async fn add_relationship(id: Id, related: Id, relationship: Relationship) {
let r = (related, relationship);
let mut relationships = GLOBALS.relationships.write().await;
relationships
.entry(id)
.and_modify(|vec| {
if !vec.contains(&r) {
vec.push(r.clone());
}
})
.or_insert_with(|| vec![r]);
}
pub fn get_replies_sync(id: Id) -> Vec<Id> {
let mut output: Vec<Id> = Vec::new();
if let Some(vec) = GLOBALS.relationships.blocking_read().get(&id) {
for (id, relationship) in vec.iter() {
if *relationship == Relationship::Reply {
output.push(*id);
}
}
}
output
}
// FIXME - this allows people to react many times to the same event, and
// it counts them all!
pub fn get_reactions_sync(id: Id) -> Vec<(char, usize)> {
let mut output: HashMap<char, usize> = HashMap::new();
if let Some(relationships) = GLOBALS.relationships.blocking_read().get(&id) {
for (_id, relationship) in relationships.iter() {
if let Relationship::Reaction(reaction) = relationship {
if let Some(ch) = reaction.chars().next() {
output
.entry(ch)
.and_modify(|count| *count += 1)
.or_insert_with(|| 1);
} else {
output
.entry('+') // if empty, presumed to be an upvote
.and_modify(|count| *count += 1)
.or_insert_with(|| 1);
}
}
}
}
let mut v: Vec<(char, usize)> = output.iter().map(|(c, u)| (*c, *u)).collect();
v.sort();
v
}
pub fn get_deletion_sync(id: Id) -> Option<String> {
if let Some(relationships) = GLOBALS.relationships.blocking_read().get(&id) {
for (_id, relationship) in relationships.iter() {
if let Relationship::Deletion(deletion) = relationship {
return Some(deletion.clone());
}
}
}
None
}
pub fn get_your_nprofile() -> Option<Profile> {
let public_key = match GLOBALS.signer.blocking_read().public_key() {
Some(pk) => pk,
None => return None,
};
let mut profile = Profile {
pubkey: public_key,
relays: Vec::new(),
};
for (url, _) in GLOBALS
.relays
.blocking_read()
.iter()
.filter(|(_, r)| r.post)
{
profile.relays.push(url.to_owned())
}
Some(profile)
}
}