tangled
alpha
login
or
join now
parakeet.at
/
parakeet
63
fork
atom
Parakeet is a Rust-based Bluesky AppServer aiming to implement most of the functionality required to support the Bluesky client
appview
atproto
bluesky
rust
appserver
63
fork
atom
overview
issues
12
pulls
pipelines
feat: nix
mia.omg.lol
3 weeks ago
4657ee2d
aae0e9c6
verified
This commit was signed with the committer's
known signature
.
mia.omg.lol
SSH Key Fingerprint:
SHA256:eb+NhC0QEl+XKRuFP/97oH6LEz0TXTKPXGDIAI5y7CQ=
+480
-11
9 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
crates
consumer
src
config.rs
main.rs
parakeet-index
Cargo.toml
build.rs
flake.lock
flake.nix
nix
services.nix
+24
-6
Cargo.lock
···
197
197
source = "registry+https://github.com/rust-lang/crates.io-index"
198
198
checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43"
199
199
dependencies = [
200
200
-
"bindgen",
200
200
+
"bindgen 0.69.5",
201
201
"cc",
202
202
"cmake",
203
203
"dunce",
···
370
370
"shlex",
371
371
"syn",
372
372
"which",
373
373
+
]
374
374
+
375
375
+
[[package]]
376
376
+
name = "bindgen"
377
377
+
version = "0.72.1"
378
378
+
source = "registry+https://github.com/rust-lang/crates.io-index"
379
379
+
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
380
380
+
dependencies = [
381
381
+
"bitflags 2.8.0",
382
382
+
"cexpr",
383
383
+
"clang-sys",
384
384
+
"itertools 0.12.1",
385
385
+
"proc-macro2",
386
386
+
"quote",
387
387
+
"regex",
388
388
+
"rustc-hash 2.1.1",
389
389
+
"shlex",
390
390
+
"syn",
373
391
]
374
392
375
393
[[package]]
···
2129
2147
2130
2148
[[package]]
2131
2149
name = "librocksdb-sys"
2132
2132
-
version = "0.17.1+9.9.3"
2150
2150
+
version = "0.17.3+10.4.2"
2133
2151
source = "registry+https://github.com/rust-lang/crates.io-index"
2134
2134
-
checksum = "2b7869a512ae9982f4d46ba482c2a304f1efd80c6412a3d4bf57bb79a619679f"
2152
2152
+
checksum = "cef2a00ee60fe526157c9023edab23943fae1ce2ab6f4abb2a807c1746835de9"
2135
2153
dependencies = [
2136
2136
-
"bindgen",
2154
2154
+
"bindgen 0.72.1",
2137
2155
"bzip2-sys",
2138
2156
"cc",
2139
2157
"libc",
···
3459
3477
3460
3478
[[package]]
3461
3479
name = "rocksdb"
3462
3462
-
version = "0.23.0"
3480
3480
+
version = "0.24.0"
3463
3481
source = "registry+https://github.com/rust-lang/crates.io-index"
3464
3464
-
checksum = "26ec73b20525cb235bad420f911473b69f9fe27cc856c5461bccd7e4af037f43"
3482
3482
+
checksum = "ddb7af00d2b17dbd07d82c0063e25411959748ff03e8d4f96134c2ff41fce34f"
3465
3483
dependencies = [
3466
3484
"libc",
3467
3485
"librocksdb-sys",
+7
Cargo.toml
···
2
2
resolver = "2"
3
3
4
4
members = ["crates/*"]
5
5
+
6
6
+
[workspace.package]
7
7
+
version = "0.1.0"
8
8
+
edition = "2024"
9
9
+
10
10
+
[workspace.metadata.crane]
11
11
+
name = "parakeet"
+6
crates/consumer/src/config.rs
···
35
35
pub struct ConfigInstruments {
36
36
#[serde(default)]
37
37
pub log_json: bool,
38
38
+
#[serde(default = "default_metrics_port")]
39
39
+
pub metrics_port: u16,
38
40
}
39
41
40
42
#[derive(Debug, Deserialize)]
···
73
75
#[serde(default = "default_download_buffer")]
74
76
pub download_buffer: usize,
75
77
pub download_tmp_dir: String,
78
78
+
}
79
79
+
80
80
+
fn default_metrics_port() -> u16 {
81
81
+
9000
76
82
}
77
83
78
84
fn default_backfill_workers() -> u8 {
+7
-2
crates/consumer/src/main.rs
···
18
18
19
19
#[tokio::main]
20
20
async fn main() -> eyre::Result<()> {
21
21
-
PrometheusBuilder::new().install()?;
22
22
-
23
21
let cli = cmd::parse();
24
22
let conf = config::load_config()?;
23
23
+
24
24
+
PrometheusBuilder::new()
25
25
+
.with_http_listener(std::net::SocketAddr::new(
26
26
+
[0, 0, 0, 0].into(),
27
27
+
conf.instruments.metrics_port,
28
28
+
))
29
29
+
.install()?;
25
30
26
31
instrumentation::init_instruments(&conf.instruments);
27
32
let user_agent = build_ua(&conf.ua_contact);
+2
-2
crates/parakeet-index/Cargo.toml
···
19
19
opentelemetry = { version = "0.31.0", optional = true }
20
20
opentelemetry-otlp = { version = "0.31.0", features = ["reqwest-rustls"], optional = true }
21
21
opentelemetry_sdk = { version = "0.31.0", optional = true }
22
22
-
rocksdb = { version = "0.23", default-features = false, features = ["lz4", "bindgen-runtime"], optional = true }
22
22
+
rocksdb = { version = "0.24", default-features = false, features = ["lz4", "bindgen-runtime"], optional = true }
23
23
serde = { version = "1.0.217", features = ["derive"], optional = true }
24
24
tokio = { version = "1.42.0", features = ["full"], optional = true }
25
25
tonic-health = { version = "0.13.0", optional = true }
···
47
47
"dep:tracing",
48
48
"dep:tracing-subscriber",
49
49
"dep:tracing-opentelemetry"
50
50
-
]
50
50
+
]
+4
-1
crates/parakeet-index/build.rs
···
1
1
fn main() -> Result<(), Box<dyn std::error::Error>> {
2
2
-
tonic_build::configure().compile_protos(&["proto/parakeet.proto"], &[""])?;
2
2
+
tonic_build::configure().compile_protos(
3
3
+
&[std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("proto/parakeet.proto")],
4
4
+
&[std::path::Path::new(env!("CARGO_MANIFEST_DIR"))],
5
5
+
)?;
3
6
4
7
Ok(())
5
8
}
+98
flake.lock
···
1
1
+
{
2
2
+
"nodes": {
3
3
+
"crane": {
4
4
+
"locked": {
5
5
+
"lastModified": 1768319649,
6
6
+
"narHash": "sha256-VFkNyxHxkqGp8gf8kfFMW1j6XeBy609kv6TE9uF/0Js=",
7
7
+
"owner": "ipetkov",
8
8
+
"repo": "crane",
9
9
+
"rev": "4b6527687cfd20da3c2ef8287e01b74c2d6c705b",
10
10
+
"type": "github"
11
11
+
},
12
12
+
"original": {
13
13
+
"owner": "ipetkov",
14
14
+
"repo": "crane",
15
15
+
"type": "github"
16
16
+
}
17
17
+
},
18
18
+
"flake-utils": {
19
19
+
"inputs": {
20
20
+
"systems": "systems"
21
21
+
},
22
22
+
"locked": {
23
23
+
"lastModified": 1731533236,
24
24
+
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
25
25
+
"owner": "numtide",
26
26
+
"repo": "flake-utils",
27
27
+
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
28
28
+
"type": "github"
29
29
+
},
30
30
+
"original": {
31
31
+
"owner": "numtide",
32
32
+
"repo": "flake-utils",
33
33
+
"type": "github"
34
34
+
}
35
35
+
},
36
36
+
"nixpkgs": {
37
37
+
"locked": {
38
38
+
"lastModified": 1768395095,
39
39
+
"narHash": "sha256-ZhuYJbwbZT32QA95tSkXd9zXHcdZj90EzHpEXBMabaw=",
40
40
+
"owner": "nixos",
41
41
+
"repo": "nixpkgs",
42
42
+
"rev": "13868c071cc73a5e9f610c47d7bb08e5da64fdd5",
43
43
+
"type": "github"
44
44
+
},
45
45
+
"original": {
46
46
+
"owner": "nixos",
47
47
+
"ref": "nixpkgs-unstable",
48
48
+
"repo": "nixpkgs",
49
49
+
"type": "github"
50
50
+
}
51
51
+
},
52
52
+
"root": {
53
53
+
"inputs": {
54
54
+
"crane": "crane",
55
55
+
"flake-utils": "flake-utils",
56
56
+
"nixpkgs": "nixpkgs",
57
57
+
"rust-overlay": "rust-overlay"
58
58
+
}
59
59
+
},
60
60
+
"rust-overlay": {
61
61
+
"inputs": {
62
62
+
"nixpkgs": [
63
63
+
"nixpkgs"
64
64
+
]
65
65
+
},
66
66
+
"locked": {
67
67
+
"lastModified": 1769222645,
68
68
+
"narHash": "sha256-gu6oZ86zLudBZMq8LL1qdtYt/S69GV5keQVXdvBrVSU=",
69
69
+
"owner": "oxalica",
70
70
+
"repo": "rust-overlay",
71
71
+
"rev": "22da29e7f3d8cff75009cbbcf992c7cb66920cfd",
72
72
+
"type": "github"
73
73
+
},
74
74
+
"original": {
75
75
+
"owner": "oxalica",
76
76
+
"repo": "rust-overlay",
77
77
+
"type": "github"
78
78
+
}
79
79
+
},
80
80
+
"systems": {
81
81
+
"locked": {
82
82
+
"lastModified": 1681028828,
83
83
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
84
84
+
"owner": "nix-systems",
85
85
+
"repo": "default",
86
86
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
87
87
+
"type": "github"
88
88
+
},
89
89
+
"original": {
90
90
+
"owner": "nix-systems",
91
91
+
"repo": "default",
92
92
+
"type": "github"
93
93
+
}
94
94
+
}
95
95
+
},
96
96
+
"root": "root",
97
97
+
"version": 7
98
98
+
}
+145
flake.nix
···
1
1
+
{
2
2
+
description = "Parakeet - a Rust-based Bluesky AppView for Bluesky client";
3
3
+
4
4
+
inputs = {
5
5
+
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
6
6
+
crane.url = "github:ipetkov/crane";
7
7
+
flake-utils.url = "github:numtide/flake-utils";
8
8
+
rust-overlay = {
9
9
+
url = "github:oxalica/rust-overlay";
10
10
+
inputs.nixpkgs.follows = "nixpkgs";
11
11
+
};
12
12
+
};
13
13
+
14
14
+
outputs =
15
15
+
{
16
16
+
self,
17
17
+
nixpkgs,
18
18
+
crane,
19
19
+
flake-utils,
20
20
+
rust-overlay,
21
21
+
...
22
22
+
}:
23
23
+
flake-utils.lib.eachDefaultSystem (
24
24
+
system:
25
25
+
let
26
26
+
pkgs = import nixpkgs {
27
27
+
inherit system;
28
28
+
overlays = [ (import rust-overlay) ];
29
29
+
};
30
30
+
31
31
+
inherit (pkgs) lib;
32
32
+
inherit (lib.fileset) toSource unions union;
33
33
+
34
34
+
craneLib = (crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.stable.latest.default);
35
35
+
src = toSource {
36
36
+
root = ./.;
37
37
+
fileset = unions [ (craneLib.fileset.commonCargoSources ./.) ];
38
38
+
};
39
39
+
40
40
+
commonArgs = {
41
41
+
inherit src;
42
42
+
strictDeps = true;
43
43
+
44
44
+
nativeBuildInputs = with pkgs; [ pkg-config ];
45
45
+
buildInputs = with pkgs; [
46
46
+
clang
47
47
+
libclang
48
48
+
openssl
49
49
+
protobuf
50
50
+
];
51
51
+
52
52
+
CLANG_PATH = "${pkgs.clang}/bin/clang";
53
53
+
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
54
54
+
PROTOC = "${pkgs.protobuf}/bin/protoc";
55
55
+
PROTOC_INCLUDE = "${pkgs.protobuf}/include";
56
56
+
};
57
57
+
58
58
+
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
59
59
+
60
60
+
individualCrateArgs = commonArgs // {
61
61
+
inherit cargoArtifacts;
62
62
+
inherit (craneLib.crateNameFromCargoToml { inherit src; }) version;
63
63
+
doCheck = false;
64
64
+
};
65
65
+
66
66
+
fileSetForCrate =
67
67
+
crate: add:
68
68
+
toSource {
69
69
+
root = ./.;
70
70
+
fileset = union (unions [
71
71
+
./Cargo.lock
72
72
+
./Cargo.toml
73
73
+
(craneLib.fileset.commonCargoSources ./crates/lexica)
74
74
+
(craneLib.fileset.commonCargoSources ./crates/parakeet-db)
75
75
+
(craneLib.fileset.commonCargoSources ./crates/parakeet-index)
76
76
+
./crates/parakeet-index/proto
77
77
+
(craneLib.fileset.commonCargoSources crate)
78
78
+
]) add;
79
79
+
};
80
80
+
81
81
+
parakeet-appview = craneLib.buildPackage (
82
82
+
individualCrateArgs
83
83
+
// {
84
84
+
pname = "parakeet";
85
85
+
cargoExtraArgs = "-p parakeet";
86
86
+
src = fileSetForCrate ./crates/parakeet (unions [
87
87
+
./migrations
88
88
+
(craneLib.fileset.commonCargoSources ./crates/dataloader-rs)
89
89
+
(craneLib.fileset.commonCargoSources ./crates/did-resolver)
90
90
+
(craneLib.fileset.commonCargoSources ./crates/parakeet)
91
91
+
./crates/parakeet/src/sql
92
92
+
]);
93
93
+
}
94
94
+
);
95
95
+
96
96
+
parakeet-consumer = craneLib.buildPackage (
97
97
+
individualCrateArgs
98
98
+
// {
99
99
+
pname = "consumer";
100
100
+
cargoExtraArgs = "-p consumer";
101
101
+
src = fileSetForCrate ./crates/consumer (unions [
102
102
+
./crates/did-resolver
103
103
+
./crates/consumer/src/db/sql
104
104
+
]);
105
105
+
}
106
106
+
);
107
107
+
108
108
+
parakeet-index = craneLib.buildPackage (
109
109
+
individualCrateArgs
110
110
+
// {
111
111
+
pname = "parakeet-index";
112
112
+
cargoExtraArgs = "-p parakeet-index --features server";
113
113
+
src = fileSetForCrate ./crates/parakeet-index (unions [ ]);
114
114
+
}
115
115
+
);
116
116
+
in
117
117
+
{
118
118
+
packages = {
119
119
+
default = parakeet-appview;
120
120
+
inherit parakeet-appview parakeet-consumer parakeet-index;
121
121
+
};
122
122
+
123
123
+
apps = {
124
124
+
parakeet-appview = flake-utils.lib.mkApp { drv = parakeet-appview; };
125
125
+
parakeet-consumer = flake-utils.lib.mkApp { drv = parakeet-consumer; };
126
126
+
parakeet-index = flake-utils.lib.mkApp { drv = parakeet-index; };
127
127
+
};
128
128
+
129
129
+
devShells.default = craneLib.devShell {
130
130
+
packages = with pkgs; [
131
131
+
diesel-cli
132
132
+
protobuf
133
133
+
];
134
134
+
};
135
135
+
}
136
136
+
)
137
137
+
// flake-utils.lib.eachDefaultSystemPassThrough (system: {
138
138
+
nixosModules = {
139
139
+
default = import ./nix/services.nix {
140
140
+
inherit system;
141
141
+
parakeetSelf = self;
142
142
+
};
143
143
+
};
144
144
+
});
145
145
+
}
+187
nix/services.nix
···
1
1
+
{ parakeetSelf, system, ... }:
2
2
+
{
3
3
+
config,
4
4
+
lib,
5
5
+
pkgs,
6
6
+
...
7
7
+
}:
8
8
+
9
9
+
let
10
10
+
inherit (lib)
11
11
+
getExe
12
12
+
mkEnableOption
13
13
+
mkIf
14
14
+
mkOption
15
15
+
types
16
16
+
;
17
17
+
18
18
+
thisSystemPackages = parakeetSelf.packages.${system};
19
19
+
20
20
+
cfg = config.services.parakeet;
21
21
+
anyEnabled = cfg.appview.enable || cfg.consumer.enable || cfg.index.enable;
22
22
+
23
23
+
settingsFormat = pkgs.formats.toml { };
24
24
+
25
25
+
toml = {
26
26
+
appview = settingsFormat.generate "Config-appview.toml" cfg.appview.settings;
27
27
+
consumer = settingsFormat.generate "Config-consumer.toml" cfg.consumer.settings;
28
28
+
index = settingsFormat.generate "Config-index.toml" cfg.index.settings;
29
29
+
};
30
30
+
31
31
+
buildService =
32
32
+
sub:
33
33
+
let
34
34
+
fullName = "parakeet-${sub}";
35
35
+
thisCfg = cfg.${sub};
36
36
+
thisToml = toml.${sub};
37
37
+
in
38
38
+
{
39
39
+
description = "Parakeet ${sub}";
40
40
+
41
41
+
after = [ "network-online.target" ];
42
42
+
wants = [ "network-online.target" ];
43
43
+
wantedBy = [ "multi-user.target" ];
44
44
+
45
45
+
preStart = "cp -f ${thisToml} $STATE_DIRECTORY/Config.toml";
46
46
+
47
47
+
serviceConfig = {
48
48
+
User = "parakeet";
49
49
+
Group = "parakeet";
50
50
+
Restart = "always";
51
51
+
ExecStart = "${getExe thisCfg.package}";
52
52
+
53
53
+
RuntimeDirectory = fullName;
54
54
+
StateDirectory = fullName;
55
55
+
WorkingDirectory = "/var/lib/${fullName}";
56
56
+
57
57
+
Environment = [ "RUST_LOG=${thisCfg.settings.RUST_LOG}" ];
58
58
+
EnvironmentFile = mkIf (thisCfg.environmentFile != null) thisCfg.environmentFile;
59
59
+
};
60
60
+
};
61
61
+
in
62
62
+
{
63
63
+
options.services.parakeet = {
64
64
+
appview = {
65
65
+
enable = mkEnableOption "Parakeet Appview";
66
66
+
67
67
+
package = mkOption {
68
68
+
type = types.package;
69
69
+
default = thisSystemPackages.parakeet-appview;
70
70
+
description = "The parakeet-appview package to use";
71
71
+
};
72
72
+
73
73
+
environmentFile = mkOption {
74
74
+
type = types.nullOr types.path;
75
75
+
default = null;
76
76
+
description = "The environment file to use for parakeet-appview";
77
77
+
};
78
78
+
79
79
+
settings = mkOption {
80
80
+
type = types.submodule {
81
81
+
freeformType = settingsFormat.type;
82
82
+
83
83
+
options = {
84
84
+
RUST_LOG = mkOption {
85
85
+
type = types.str;
86
86
+
default = "info";
87
87
+
description = "Logging level and filters to use. Uses tracing-subscriber EnvFilter";
88
88
+
};
89
89
+
};
90
90
+
};
91
91
+
};
92
92
+
};
93
93
+
94
94
+
consumer = {
95
95
+
enable = mkEnableOption "Parakeet Consumer";
96
96
+
97
97
+
package = mkOption {
98
98
+
type = types.package;
99
99
+
default = thisSystemPackages.parakeet-consumer;
100
100
+
description = "The parakeet-consumer package to use";
101
101
+
};
102
102
+
103
103
+
environmentFile = mkOption {
104
104
+
type = lib.types.nullOr lib.types.path;
105
105
+
default = null;
106
106
+
description = "The environment file to use for parakeet-consumer";
107
107
+
};
108
108
+
109
109
+
settings = mkOption {
110
110
+
type = types.submodule {
111
111
+
freeformType = settingsFormat.type;
112
112
+
113
113
+
options = {
114
114
+
RUST_LOG = mkOption {
115
115
+
type = types.str;
116
116
+
default = "info";
117
117
+
description = "Logging level and filters to use. Uses tracing-subscriber EnvFilter";
118
118
+
};
119
119
+
120
120
+
modes = mkOption {
121
121
+
type = types.listOf types.str;
122
122
+
default = [ "indexer" ];
123
123
+
description = "Modes to run the consumer in. Accepts one or more of backfill, indexer, labels.";
124
124
+
};
125
125
+
};
126
126
+
};
127
127
+
};
128
128
+
};
129
129
+
130
130
+
index = {
131
131
+
enable = mkEnableOption "Parakeet Index";
132
132
+
133
133
+
package = mkOption {
134
134
+
type = types.package;
135
135
+
default = thisSystemPackages.parakeet-index;
136
136
+
description = "The parakeet-index package to use";
137
137
+
};
138
138
+
139
139
+
environmentFile = mkOption {
140
140
+
type = lib.types.nullOr lib.types.path;
141
141
+
default = null;
142
142
+
description = "The environment file to use for parakeet-index";
143
143
+
};
144
144
+
145
145
+
settings = mkOption {
146
146
+
type = types.submodule {
147
147
+
freeformType = settingsFormat.type;
148
148
+
149
149
+
options = {
150
150
+
RUST_LOG = mkOption {
151
151
+
type = types.str;
152
152
+
default = "info";
153
153
+
description = "Logging level and filters to use. Uses tracing-subscriber EnvFilter";
154
154
+
};
155
155
+
};
156
156
+
};
157
157
+
};
158
158
+
};
159
159
+
};
160
160
+
161
161
+
config = {
162
162
+
environment.systemPackages = mkIf cfg.consumer.enable [
163
163
+
thisSystemPackages.parakeet-consumer
164
164
+
];
165
165
+
166
166
+
systemd.services.parakeet-appview = mkIf cfg.appview.enable (buildService "appview");
167
167
+
168
168
+
systemd.services.parakeet-consumer = mkIf cfg.consumer.enable (
169
169
+
lib.recursiveUpdate (buildService "consumer") {
170
170
+
serviceConfig.ExecStart = "${getExe thisSystemPackages.parakeet-consumer} ${
171
171
+
lib.strings.join " " (lib.map (x: "--${x}") cfg.consumer.settings.modes)
172
172
+
}";
173
173
+
}
174
174
+
);
175
175
+
176
176
+
systemd.services.parakeet-index = mkIf cfg.index.enable (buildService "index");
177
177
+
178
178
+
users = mkIf anyEnabled {
179
179
+
users.parakeet = {
180
180
+
group = "parakeet";
181
181
+
isSystemUser = true;
182
182
+
};
183
183
+
184
184
+
groups.parakeet = { };
185
185
+
};
186
186
+
};
187
187
+
}