diff options
-rw-r--r-- | flake.nix | 62 | ||||
-rw-r--r-- | onboarding.json | 33 | ||||
-rw-r--r-- | src/database/file/mod.rs | 2 | ||||
-rw-r--r-- | src/frontend/mod.rs | 13 |
4 files changed, 75 insertions, 35 deletions
diff --git a/flake.nix b/flake.nix index c2d3b30..c879a7f 100644 --- a/flake.nix +++ b/flake.nix @@ -62,11 +62,22 @@ example = "info"; description = "Specify the server verbosity level. Uses RUST_LOG environment variable internally."; }; - redisUri = mkOption { - type = types.nullOr types.str; - default = null; - example = "redis://192.168.1.200:6379/"; - description = "Set the Redis instance used as backing storage. If null, Redis will be configured on localhost. Use services.redis to change parameters."; + backendUri = mkOption { + type = types.str; + default = "file:///var/lib/kittybox/data"; + example = "redis://192.168.1.200:6379"; + description = '' + Set the backend used for storing data. Available backends are: + - file:// - static folder backend (recommended) + - redis:// - Redis backend + + Make sure that if you are using the file backend, the state + directory is accessible by Kittybox. By default, the unit config + uses DynamicUser=true, which prevents the unit from accessing + data outside of its directory. It is recommended to use a + bind-mount to /var/lib/private/kittybox if you require the state + directory to reside elsewhere. + ''; }; tokenEndpoint = mkOption { type = types.str; @@ -124,7 +135,7 @@ restartTriggers = [ cfg.package - cfg.redisUri cfg.tokenEndpoint + cfg.backendUri cfg.tokenEndpoint cfg.authorizationEndpoint cfg.internalTokenFile cfg.bind cfg.port @@ -137,7 +148,8 @@ MEDIA_ENDPOINT = cfg.mediaEndpoint; MICROSUB_ENDPOINT = cfg.microsubServer; WEBMENTION_ENDPOINT = cfg.webmentionEndpoint; - REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri; + #REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri; + BACKEND_URI = cfg.backendUri; RUST_LOG = "${cfg.logLevel}"; }; @@ -152,11 +164,9 @@ serviceConfig = { DynamicUser = true; + StateDirectory = "kittybox"; }; }; - services.redis = lib.mkIf (cfg.redisUri == null) { - enable = true; - }; }; }; } // forAllSystems (system: let @@ -195,7 +205,7 @@ defaultPackage = self.packages.${system}.kittybox; checks = { - nixos-test = pkgs.nixosTest ({ lib }: { + nixos-test = (pkgs.nixosTest ({ lib }: { name = "nixos-kittybox"; nodes = { @@ -209,6 +219,7 @@ # make an e2e test for common workflows (e.g. making a post) tokenEndpoint = "https://example.com"; authorizationEndpoint = "https://example.com"; + logLevel = "debug"; }; environment.systemPackages = with pkgs; [ @@ -218,38 +229,21 @@ }; testScript = '' - import json - kittybox.start() kittybox.wait_for_unit("default.target") with subtest("Verify that Kittybox started correctly..."): kittybox.succeed("curl --silent http://localhost:8080/micropub") with subtest("Onboarding should correctly work..."): - onboarding_json = { - "user": { - "type": ["h-card"], - "properties": { - "name": ["Vika"], - "pronoun": ["she/her"], - "url": ["https://twitter.com/VikaNezrimaya"], - "note": ["Just a simple girl. Do I even exist or am I a vestige of the past long gone?"] - } - }, - "first_post": { - "type": ["h-entry"], - "properties": { - "content": ["Hello!"] - } - }, - "blog_name": "Test Hideout", - "feeds": [] - } - kittybox.succeed("echo '{}' | curl --silent http://localhost:8080/ -d@- -H 'Content-Type: application/json'".format(json.dumps(onboarding_json).replace("'", "'\''$"))) + # Here we rely on a fact that the /nix/store is shared between the host and the VM + kittybox.succeed("curl -vvv http://localhost:8080/ -d${./onboarding.json}") # Testing for a known string is the easiest way to determine that the onboarding worked kittybox.succeed("curl --silent http://localhost:8080/ | grep 'vestige of the past long gone'") ''; - }); + })) + # This test is broken! For some reason the file locks don't seem to work and hang the executable instead. + #.overrideAttrs(o: { meta.broken = true; }) + ; }; devShell = pkgs.mkShell { diff --git a/onboarding.json b/onboarding.json new file mode 100644 index 0000000..04acbf8 --- /dev/null +++ b/onboarding.json @@ -0,0 +1,33 @@ +{ + "user": { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Vika" + ], + "pronoun": [ + "she/her" + ], + "url": [ + "https://twitter.com/VikaNezrimaya" + ], + "note": [ + "Just a simple girl. Do I even exist or am I a vestige of the past long gone?" + ] + } + }, + "first_post": { + "type": [ + "h-entry" + ], + "properties": { + "content": [ + "Hello!" + ] + } + }, + "blog_name": "Test Hideout", + "feeds": [] +} diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs index acbb44b..f58317e 100644 --- a/src/database/file/mod.rs +++ b/src/database/file/mod.rs @@ -483,8 +483,10 @@ impl Storage for FileStorage { .create(true) .open(&path).await?; let mut lock = get_lockable_file(file).await; + log::debug!("Created a lock. Locking for writing..."); let mut guard = lock.write()?; + log::debug!("Locked. Writing."); let mut content = String::new(); guard.read_to_string(&mut content).await?; let mut settings: HashMap<String, String> = if content.len() == 0 { diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 37420ac..890879c 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -120,6 +120,8 @@ struct OnboardingData { pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S>>) -> Result { use serde_json::json; + log::debug!("Entering onboarding receiver..."); + // This cannot error out as the URL must be valid. Or there is something horribly wrong // and we shouldn't serve this request anyway. <dyn AsMut<tide::http::Request>>::as_mut(&mut req) @@ -127,7 +129,9 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S .set_scheme("https") .unwrap(); + log::debug!("Parsing the body..."); let body = req.body_json::<OnboardingData>().await?; + log::debug!("Body parsed!"); let backend = &req.state().storage; #[cfg(any(not(debug_assertions), test))] @@ -135,6 +139,8 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S #[cfg(all(debug_assertions, not(test)))] let me = url::Url::parse("https://localhost:8080/").unwrap(); + log::debug!("me value: {:?}", me); + if get_post_from_database(backend, me.as_str(), None, &None) .await .is_ok() @@ -149,6 +155,7 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S let user = crate::indieauth::User::new(me.as_str(), "https://kittybox.fireburn.ru/", "create"); + log::debug!("Setting the site name to {}", &body.blog_name); backend .set_setting("site_name", user.me.as_str(), &body.blog_name) .await?; @@ -173,9 +180,13 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S // post function is just to ensure that the posts will be syndicated // and inserted into proper feeds. Here, we don't have a need for this, // since the h-card is DIRECTLY accessible via its own URL. + log::debug!("Saving the h-card..."); backend.put_post(&hcard, me.as_str()).await?; + log::debug!("Creating feeds..."); for feed in body.feeds { + if &feed.name == "" || &feed.slug == "" { continue }; + log::debug!("Creating feed {} with slug {}", &feed.name, &feed.slug); let (_, feed) = crate::micropub::normalize_mf2( json!({ "type": ["h-feed"], @@ -186,7 +197,7 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S backend.put_post(&feed, me.as_str()).await?; } - + log::debug!("Saving the h-entry..."); // This basically puts the h-entry post through the normal creation process. // We need to insert it into feeds and optionally send a notification to everywhere. req.set_ext(user); |