+164
-28
src/actor_store/mod.rs
+164
-28
src/actor_store/mod.rs
···
10
use std::sync::Arc;
11
12
use anyhow::{Context as _, Result};
13
-
use atrium_crypto::keypair::{Export as _, Secp256k1Keypair};
14
use sqlx::SqlitePool;
15
16
use crate::config::RepoConfig;
17
18
/// Resources required by the actor store.
19
pub(crate) struct ActorStoreResources {
20
/// Configuration for the repo.
21
pub(crate) config: RepoConfig,
22
/// Background task queue (we'll need to implement this later).
23
pub(crate) background_queue: Arc<()>, // TODO: Placeholder until we implement a proper queue
24
}
···
46
/// Reader for actor data.
47
pub(crate) struct ActorStoreReader {
48
/// The DID of the actor.
49
-
did: String,
50
/// The database connection.
51
-
db: SqlitePool,
52
/// The actor's keypair.
53
-
keypair: Arc<Secp256k1Keypair>,
54
/// Resources for the actor store.
55
-
resources: Arc<ActorStoreResources>,
56
}
57
58
/// Writer for actor data with transaction support.
59
pub(crate) struct ActorStoreWriter {
60
/// The DID of the actor.
61
-
did: String,
62
/// The database connection.
63
-
db: SqlitePool,
64
/// The actor's keypair.
65
-
keypair: Arc<Secp256k1Keypair>,
66
/// Resources for the actor store.
67
-
resources: Arc<ActorStoreResources>,
68
}
69
70
/// Transactor for actor data.
71
pub(crate) struct ActorStoreTransactor {
72
/// The DID of the actor.
73
-
did: String,
74
/// The database connection.
75
-
db: SqlitePool,
76
/// The actor's keypair.
77
-
keypair: Arc<Secp256k1Keypair>,
78
/// Resources for the actor store.
79
-
resources: Arc<ActorStoreResources>,
80
}
81
82
impl ActorStore {
···
91
}
92
}
93
94
/// Get the location of a DID's data.
95
pub(crate) async fn get_location(&self, did: &str) -> Result<ActorLocation> {
96
let did_hash = sha256_hex(did).await?;
···
112
}
113
114
/// Get the keypair for an actor.
115
-
pub(crate) async fn keypair(&self, did: &str) -> Result<Arc<Secp256k1Keypair>> {
116
let location = self.get_location(did).await?;
117
let priv_key = tokio::fs::read(&location.key_location).await?;
118
-
let keypair = Secp256k1Keypair::import(&priv_key)?;
119
Ok(Arc::new(keypair))
120
}
121
···
148
let db = self.open_db(did).await?;
149
let keypair = self.keypair(did).await?;
150
let resources = Arc::new(self.resources.clone());
151
152
let reader = ActorStoreReader {
153
-
did: did.to_string(),
154
db,
155
keypair,
156
resources,
···
164
where
165
F: FnOnce(ActorStoreTransactor) -> Result<T>,
166
{
167
-
let db = self.open_db(did).await?;
168
let keypair = self.keypair(did).await?;
169
let resources = Arc::new(self.resources.clone());
170
171
let transactor = ActorStoreTransactor {
172
-
did: did.to_string(),
173
db,
174
keypair,
175
resources,
···
186
let db = self.open_db(did).await?;
187
let keypair = self.keypair(did).await?;
188
let resources = Arc::new(self.resources.clone());
189
190
let writer = ActorStoreWriter {
191
-
did: did.to_string(),
192
db,
193
keypair,
194
resources,
···
198
}
199
200
/// Create a new actor repository.
201
-
pub(crate) async fn create(&self, did: &str, keypair: Secp256k1Keypair) -> Result<()> {
202
let location = self.get_location(did).await?;
203
204
// Create directory if it doesn't exist
···
229
Ok(())
230
}
231
232
-
// TODO: To be implemented: destroy, reserve_keypair, etc.
233
}
234
235
-
// Helper function for SHA-256 hashing
236
-
async fn sha256_hex(input: &str) -> Result<String> {
237
-
use sha2::{Digest, Sha256};
238
-
let mut hasher = Sha256::new();
239
-
hasher.update(input.as_bytes());
240
-
let result = hasher.finalize();
241
-
Ok(hex::encode(result))
242
}
243
244
impl Clone for ActorStoreResources {
245
fn clone(&self) -> Self {
246
Self {
247
config: self.config.clone(),
248
background_queue: self.background_queue.clone(),
249
}
250
}
251
}
···
10
use std::sync::Arc;
11
12
use anyhow::{Context as _, Result};
13
+
use atrium_crypto::keypair::Export as _;
14
use sqlx::SqlitePool;
15
16
+
use crate::SigningKey;
17
use crate::config::RepoConfig;
18
19
/// Resources required by the actor store.
20
pub(crate) struct ActorStoreResources {
21
/// Configuration for the repo.
22
pub(crate) config: RepoConfig,
23
+
/// Configuration for the blob store.
24
+
pub(crate) blob_config: crate::config::BlobConfig,
25
/// Background task queue (we'll need to implement this later).
26
pub(crate) background_queue: Arc<()>, // TODO: Placeholder until we implement a proper queue
27
}
···
49
/// Reader for actor data.
50
pub(crate) struct ActorStoreReader {
51
/// The DID of the actor.
52
+
pub(crate) did: String,
53
/// The database connection.
54
+
pub(crate) db: SqlitePool,
55
/// The actor's keypair.
56
+
keypair: Arc<SigningKey>,
57
/// Resources for the actor store.
58
+
pub(crate) resources: Arc<ActorStoreResources>,
59
+
/// Repository reader
60
+
pub(crate) repo: repo::RepoReader,
61
+
/// Record reader
62
+
pub(crate) record: record::RecordReader,
63
+
/// Preference reader
64
+
pub(crate) pref: preference::PreferenceReader,
65
}
66
67
/// Writer for actor data with transaction support.
68
pub(crate) struct ActorStoreWriter {
69
/// The DID of the actor.
70
+
pub(crate) did: String,
71
/// The database connection.
72
+
pub(crate) db: SqlitePool,
73
/// The actor's keypair.
74
+
keypair: Arc<SigningKey>,
75
/// Resources for the actor store.
76
+
pub(crate) resources: Arc<ActorStoreResources>,
77
+
/// Repository access
78
+
pub(crate) repo: repo::RepoTransactor,
79
+
/// Record access
80
+
pub(crate) record: record::RecordTransactor,
81
+
/// Preference access
82
+
pub(crate) pref: preference::PreferenceTransactor,
83
}
84
85
/// Transactor for actor data.
86
pub(crate) struct ActorStoreTransactor {
87
/// The DID of the actor.
88
+
pub(crate) did: String,
89
/// The database connection.
90
+
pub(crate) db: SqlitePool,
91
/// The actor's keypair.
92
+
keypair: Arc<SigningKey>,
93
/// Resources for the actor store.
94
+
pub(crate) resources: Arc<ActorStoreResources>,
95
+
/// Repository access
96
+
pub(crate) repo: repo::RepoTransactor,
97
+
/// Record access
98
+
pub(crate) record: record::RecordTransactor,
99
+
/// Preference access
100
+
pub(crate) pref: preference::PreferenceTransactor,
101
}
102
103
impl ActorStore {
···
112
}
113
}
114
115
+
/// Load an actor store based on a given DID.
116
+
pub(crate) async fn load(did: &str, resources: ActorStoreResources) -> Result<Self> {
117
+
let did_hash = sha256_hex(did).await?;
118
+
let directory = resources.config.path.join(&did_hash[0..2]).join(did);
119
+
let reserved_key_dir = directory.join("reserved_keys");
120
+
121
+
Ok(Self {
122
+
directory,
123
+
reserved_key_dir,
124
+
resources,
125
+
})
126
+
}
127
+
128
/// Get the location of a DID's data.
129
pub(crate) async fn get_location(&self, did: &str) -> Result<ActorLocation> {
130
let did_hash = sha256_hex(did).await?;
···
146
}
147
148
/// Get the keypair for an actor.
149
+
pub(crate) async fn keypair(&self, did: &str) -> Result<Arc<SigningKey>> {
150
let location = self.get_location(did).await?;
151
let priv_key = tokio::fs::read(&location.key_location).await?;
152
+
let keypair = SigningKey::import(&priv_key)?;
153
Ok(Arc::new(keypair))
154
}
155
···
182
let db = self.open_db(did).await?;
183
let keypair = self.keypair(did).await?;
184
let resources = Arc::new(self.resources.clone());
185
+
let did_str = did.to_string();
186
187
let reader = ActorStoreReader {
188
+
did: did_str.clone(),
189
+
repo: repo::RepoReader::new(
190
+
db.clone(),
191
+
did_str.clone(),
192
+
self.resources.blob_config.clone(),
193
+
),
194
+
record: record::RecordReader::new(db.clone(), did_str.clone()),
195
+
pref: preference::PreferenceReader::new(db.clone(), did_str),
196
db,
197
keypair,
198
resources,
···
206
where
207
F: FnOnce(ActorStoreTransactor) -> Result<T>,
208
{
209
let keypair = self.keypair(did).await?;
210
+
let db = self.open_db(did).await?;
211
let resources = Arc::new(self.resources.clone());
212
+
let did_str = did.to_string();
213
214
let transactor = ActorStoreTransactor {
215
+
did: did_str.clone(),
216
+
repo: repo::RepoTransactor::new(
217
+
db.clone(),
218
+
did_str.clone(),
219
+
(*keypair).clone(),
220
+
self.resources.blob_config.clone(),
221
+
),
222
+
record: record::RecordTransactor::new(
223
+
db.clone(),
224
+
db.clone(), // Using db as placeholder for blobstore
225
+
did_str.clone(),
226
+
),
227
+
pref: preference::PreferenceTransactor::new(db.clone(), did_str),
228
db,
229
keypair,
230
resources,
···
241
let db = self.open_db(did).await?;
242
let keypair = self.keypair(did).await?;
243
let resources = Arc::new(self.resources.clone());
244
+
let did_str = did.to_string();
245
246
let writer = ActorStoreWriter {
247
+
did: did_str.clone(),
248
+
repo: repo::RepoTransactor::new(
249
+
db.clone(),
250
+
did_str.clone(),
251
+
(*keypair).clone(),
252
+
self.resources.blob_config.clone(),
253
+
),
254
+
record: record::RecordTransactor::new(
255
+
db.clone(),
256
+
db.clone(), // Using db as placeholder for blobstore
257
+
did_str.clone(),
258
+
),
259
+
pref: preference::PreferenceTransactor::new(db.clone(), did_str),
260
db,
261
keypair,
262
resources,
···
266
}
267
268
/// Create a new actor repository.
269
+
pub(crate) async fn create(&self, did: &str, keypair: SigningKey) -> Result<()> {
270
let location = self.get_location(did).await?;
271
272
// Create directory if it doesn't exist
···
297
Ok(())
298
}
299
300
+
/// Destroy an actor's repository and associated data.
301
+
pub(crate) async fn destroy(&self, did: &str) -> Result<()> {
302
+
// TODO: Implement repository destruction
303
+
// - Delete all blobs for the repository
304
+
// - Remove the repository directory
305
+
todo!("Implement repository destruction")
306
+
}
307
+
308
+
/// Reserve a keypair for a DID.
309
+
pub(crate) async fn reserve_keypair(&self, did: Option<&str>) -> Result<String> {
310
+
// TODO: Implement keypair reservation
311
+
// - Generate a keypair if one doesn't exist
312
+
// - Store the keypair in the reserved_key_dir
313
+
// - Return the DID of the keypair
314
+
todo!("Implement keypair reservation")
315
+
}
316
+
317
+
/// Get a reserved keypair.
318
+
pub(crate) async fn get_reserved_keypair(
319
+
&self,
320
+
signing_key_or_did: &str,
321
+
) -> Result<Option<()>> {
322
+
// TODO: Implement getting a reserved keypair
323
+
// - Load the keypair from the reserved_key_dir
324
+
todo!("Implement getting a reserved keypair")
325
+
}
326
+
327
+
/// Clear a reserved keypair.
328
+
pub(crate) async fn clear_reserved_keypair(
329
+
&self,
330
+
key_did: &str,
331
+
did: Option<&str>,
332
+
) -> Result<()> {
333
+
// TODO: Implement clearing a reserved keypair
334
+
// - Remove the keypair file from the reserved_key_dir
335
+
todo!("Implement clearing a reserved keypair")
336
+
}
337
+
338
+
/// Store a PLC operation.
339
+
pub(crate) async fn store_plc_op(&self, did: &str, op: &[u8]) -> Result<()> {
340
+
// TODO: Implement storing a PLC operation
341
+
// - Store the operation in the actor's directory
342
+
todo!("Implement storing a PLC operation")
343
+
}
344
+
345
+
/// Get a stored PLC operation.
346
+
pub(crate) async fn get_plc_op(&self, did: &str) -> Result<Vec<u8>> {
347
+
// TODO: Implement getting a PLC operation
348
+
// - Retrieve the operation from the actor's directory
349
+
todo!("Implement getting a PLC operation")
350
+
}
351
+
352
+
/// Clear a stored PLC operation.
353
+
pub(crate) async fn clear_plc_op(&self, did: &str) -> Result<()> {
354
+
// TODO: Implement clearing a PLC operation
355
+
// - Remove the operation file from the actor's directory
356
+
todo!("Implement clearing a PLC operation")
357
+
}
358
}
359
360
+
impl ActorStoreWriter {
361
+
/// Transact with the writer.
362
+
pub(crate) async fn transact<T, F>(&self, f: F) -> Result<T>
363
+
where
364
+
F: FnOnce(ActorStoreTransactor) -> Result<T>,
365
+
{
366
+
todo!("Implement transact method for ActorStoreWriter")
367
+
}
368
}
369
370
impl Clone for ActorStoreResources {
371
fn clone(&self) -> Self {
372
Self {
373
config: self.config.clone(),
374
+
blob_config: self.blob_config.clone(),
375
background_queue: self.background_queue.clone(),
376
}
377
}
378
}
379
+
380
+
// Helper function for SHA-256 hashing
381
+
async fn sha256_hex(input: &str) -> Result<String> {
382
+
use sha2::{Digest, Sha256};
383
+
let mut hasher = Sha256::new();
384
+
hasher.update(input.as_bytes());
385
+
let result = hasher.finalize();
386
+
Ok(hex::encode(result))
387
+
}
+3
src/actor_store/preference/mod.rs
+3
src/actor_store/preference/mod.rs
+3
-3
src/actor_store/preference/transactor.rs
+3
-3
src/actor_store/preference/transactor.rs
···
5
use super::reader::{AccountPreference, PreferenceReader, pref_in_scope, pref_match_namespace};
6
7
/// Transactor for preference operations.
8
-
pub(super) struct PreferenceTransactor {
9
/// Preference reader.
10
pub reader: PreferenceReader,
11
}
12
13
impl PreferenceTransactor {
14
/// Create a new preference transactor.
15
-
pub(super) fn new(db: SqlitePool, did: String) -> Self {
16
Self {
17
reader: PreferenceReader::new(db, did),
18
}
19
}
20
21
/// Put preferences for a namespace.
22
-
pub(super) async fn put_preferences(
23
&self,
24
values: Vec<AccountPreference>,
25
namespace: &str,
···
5
use super::reader::{AccountPreference, PreferenceReader, pref_in_scope, pref_match_namespace};
6
7
/// Transactor for preference operations.
8
+
pub(crate) struct PreferenceTransactor {
9
/// Preference reader.
10
pub reader: PreferenceReader,
11
}
12
13
impl PreferenceTransactor {
14
/// Create a new preference transactor.
15
+
pub(crate) fn new(db: SqlitePool, did: String) -> Self {
16
Self {
17
reader: PreferenceReader::new(db, did),
18
}
19
}
20
21
/// Put preferences for a namespace.
22
+
pub(crate) async fn put_preferences(
23
&self,
24
values: Vec<AccountPreference>,
25
namespace: &str,
+3
src/actor_store/record/mod.rs
+3
src/actor_store/record/mod.rs
+5
src/actor_store/repo/mod.rs
+5
src/actor_store/repo/mod.rs
-3
src/config.rs
-3
src/config.rs
+8
src/main.rs
+8
src/main.rs
···
169
}
170
}
171
172
+
impl SigningKey {
173
+
/// Import from a private key.
174
+
pub fn import(key: &[u8]) -> Result<Self> {
175
+
let key = Secp256k1Keypair::import(key).context("failed to import signing key")?;
176
+
Ok(Self(Arc::new(key)))
177
+
}
178
+
}
179
+
180
impl std::ops::Deref for RotationKey {
181
type Target = Secp256k1Keypair;
182