milestone 4a: oci-container+overlay + manyfold.sh

This commit is contained in:
Leon van Kammen 2025-07-28 17:52:11 +02:00
parent a54b1703f5
commit 43e5a56d8a
5 changed files with 527 additions and 41 deletions

47
manyfold/README.md Normal file
View file

@ -0,0 +1,47 @@
# Manyfold container
The XRForge-serverimage is a pre-configured Manyfold container (reproducably via [nix](https://nixos.org) dockertools).
It also contains some extra's, to better fit an XR audience.
> To run it, see the [sysadmin](https://manyfold.app/sysadmin/) documentation of the [manyfold](https://github.com/manyfold3d/manyfold) project.
# Build the container-image
```bash
$ docker load < $(nix-build nix/docker.nix)
```
# Extra environment-variables
| environment variable | default | info |
|----------------------|------------|------------------------|
| `APPNAME` | `manyfold` | manyfold instance name |
| `THEME` | `default` | bootstrap theme |
| `NO_OVERLAYFS` | `` | disable the filesystem overlay mechanism |
| `NO_DEFAULTDB` | `` | disable the default db (activates manyfold installer) |
| `RCLONE_REMOTE` | `` | specify rclone remote name (without semicolon) to mount (by default rclone mounts+adds every rclone remote). Use this to specify a [combined](https://rclone.org/combine/) or [union](https://rclone.org/union/) remote|
# Default database / admin login
* email: `xrforge@localhost`
* login: `xrforge`
* password: `xrforge!1`
> please modify the password in the settings screen of the webinterface.
# Filesystem overlay-mechanism
The server-image will boot `manyfold/cli/manyfold.sh boot` and check for directory `/manifold` (in the container).
When found, it uses the files in there instead (`/manyfold/usr/src/app/public/404.html` instead of `/usr/src/app/public/404.html` e.g.).
# Remote model-drives
To enable rclone to mount network drives, the container must be run with FUSE-device support.
The quickest way is:
* add `-v ./manyfold/root/.config:/root/.config --cap-add SYS_ADMIN --security-opt apparmor:unconfined --device /dev/fuse` to the docker cmd
* add network drives by running `docker exec -it rclone config` in a running container
* profit!
> your drives will get automagically mounted and added to the database automagically (manifold.sh](manyfold/cli/manifold.sh) rclone_automount) during boot

View file

@ -1,43 +1,105 @@
#!/bin/sh
oci=$(which podman || which docker)
test -n "$APPNAME" || APPNAME=xrforge
db=/config/manyfold.sqlite3
# utility funcs
error(){ echocolor "[error]" "$*"; exit 1; }
echocolor(){ printf "\033[96m%s\033[0m \033[95m%s\033[0m %s\n" "$1" "$2" "$3"; }
debug(){ set -x; "$@"; set +x; }
create_config(){
test -d ./config || mkdir config
test -d ./experiences || mkdir experiences
}
colorize(){ printf "\033[96m%s\033[0m \033[95m%s\033[0m %s\n" "$1" "$2" "$3"; }
debug(){ set -x; "$@"; set +x; }
run(){
test -x ${oci} || { echo "warning: not running manyfold OCI container [install podman/docker/etc]"; exit; }
colorize "[manyfold.sh]" "$(basename ${oci}) detected..starting OCI container"
${oci} rm -f manyfold
debug ${oci} run "$@" -d -p 8790:3214 --name manyfold \
-v ./config:/config \
-v ./experiences:/experiences \
-v ./:/root \
$(template_overrides) \
echocolor "[$APPNAME]" "$(basename ${oci}) detected..starting OCI container"
${oci} rm -f xrforge
debug ${oci} run "$@" -p 8790:3214 --name xrforge \
-e SECRET_KEY_BASE=lkjwljlkwejrlkjek34k234l \
-e DATABASE_ADAPTER=sqlite3 \
-e SUDO_RUN_UNSAFELY=enabled \
-e HTTPS_ONLY=disabled \
-e MULTIUSER=enabled \
-e FEDERATION=enabled \
-e THEME=vapor \
-e PUBLIC_HOSTNAME=localhost \
-e PUBLIC_PORT=80 \
ghcr.io/manyfold3d/manyfold-solo:latest
sleep 1
patch_manyfold
--cap-add SYS_ADMIN --security-opt apparmor:unconfined --device /dev/fuse \
xrforge
#ghcr.io/manyfold3d/manyfold-solo:latest
}
template_overrides(){
cd manyfold > /dev/null && find * -type f | awk '/.*/ { printf "-v ./manyfold/"$0":/"$0" " }';
overlayfs(){
test -d /manyfold || return 0; # nothing to override
echocolor "[$APPNAME]" "applying filesystem overlay"
cd /manyfold
rsync -ravuzi * /.
}
patch_manyfold(){
colorize "[manyfold.sh]" "patching.."
${oci} exec manyfold id
db(){
default(){
test -f /manyfold/manyfold.sql && ! test -f /config/manyfold.sql && {
echocolor "[$APPNAME]" "copying default database"
test -d /config || mkdir /config
cat /manyfold/manyfold.sql | sqlite3 $db
}
}
dump(){
sqlite3 source.db ".dump" > /manyfold/manyfold.sql
}
import(){
sqlite3 $db < "$1" #/manyfold/manyfold.sql
}
"$@"
}
rclone_mount(){
libraries(){
rclone listremotes | while read remote; do
dir="${remote/:/}"
test -d /mnt/$dir || mkdir /mnt/$dir
echocolor "[$APPNAME]" "rclone: mounting $remote to /mnt/$dir"
debug rclone mount --daemon $remote /mnt/$dir -vv
debug sqlite3 $db "INSERT INTO libraries VALUES(NULL,'/mnt/$dir',DATE('NOW'),DATE('NOW'),'','','$dir',NULL,'','filesystem','','','','','','$dir',1);"
done
}
library(){
echocolor "[$APPNAME]" "rclone: mounting $RCLONE_REMOTE to /mnt/models"
test -d /mnt/models || mkdir /mnt/models
debug rclone mount --daemon ${RCLONE_REMOTE}: /mnt/models -vv
debug sqlite3 $db "INSERT INTO libraries VALUES(NULL,'/mnt/models',DATE('NOW'),DATE('NOW'),'','','$dir',NULL,'','filesystem','','','','','','models',1);"
}
test -n "$RCLONE_REMOTE" && library
test -n "$RCLONE_REMOTE" || libraries
}
set_theme(){
test -z "$THEME" && return 0 # nothing to do
echocolor "[$APPNAME]" "setting theme to '$THEME'"
debug sqlite3 /config/manyfold.sqlite3 "UPDATE settings SET value = '"$THEME"' WHERE var == 'theme';"
}
rename_app(){
echocolor "[$APPNAME]" "renaming manyfold to $APPNAME"
sed -i 's/title: Manyfold/title: '$APPNAME'/g' /usr/src/app/config/locales/*.yml
sed -i 's|powered_by_html:.*|powered_by_html: Powered by <a href="https://manifold.app" target="_blank">Manyfold</a>, <a href="https://xrfragment.org">XR Fragments</a> and <a href="https://forgejo.isvery.ninja/coderofsalvation/xrforge">XR Forge</a>|g' /usr/src/app/config/locales/*.yml
}
# The new entrypoint of the docker
boot(){
echocolor "[$APPNAME]" "booting..."
test -z "$NO_OVERLAYFS" && overlayfs
test -z "$NO_DEFAULTDB" && db default
rename_app
set_theme
rclone_mount
exec "$@" # exec prevents error 's6-overlay-suexec: fatal: can only run as pid 1'
}
is_inside_container(){
@ -45,13 +107,11 @@ is_inside_container(){
}
usage(){
colorize "Usage:" manyfold.sh "<cmd>"
colorize "Cmds:"
colorize " " "run [-d] " "# runs a OCI container (needs podman/docker)"
echocolor "Usage:" manyfold.sh "<cmd>"
echocolor "Cmds:"
echocolor " " "run [-d] " "# runs a OCI container (needs podman/docker)"
exit 0
}
is_inside_container || {
test -n "$1" && "$@"
test -n "$1" || usage
}
test -n "$1" && "$@"
test -n "$1" || usage

339
manyfold/manyfold.sql Normal file
View file

@ -0,0 +1,339 @@
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "data_migrations" ("version" varchar NOT NULL PRIMARY KEY);
INSERT INTO data_migrations VALUES('20221214230757');
INSERT INTO data_migrations VALUES('20221220223040');
INSERT INTO data_migrations VALUES('20230221174212');
INSERT INTO data_migrations VALUES('20230308006000');
INSERT INTO data_migrations VALUES('20230612080306');
INSERT INTO data_migrations VALUES('20230613134254');
INSERT INTO data_migrations VALUES('20230617222353');
INSERT INTO data_migrations VALUES('20230628194944');
INSERT INTO data_migrations VALUES('20240319155526');
INSERT INTO data_migrations VALUES('20240322150022');
INSERT INTO data_migrations VALUES('20240615085913');
INSERT INTO data_migrations VALUES('20240731165647');
INSERT INTO data_migrations VALUES('20240802094448');
INSERT INTO data_migrations VALUES('20240805111500');
INSERT INTO data_migrations VALUES('20240830121749');
INSERT INTO data_migrations VALUES('20240830151650');
INSERT INTO data_migrations VALUES('20240904152358');
INSERT INTO data_migrations VALUES('20240909100000');
INSERT INTO data_migrations VALUES('20240923114515');
INSERT INTO data_migrations VALUES('20241013215000');
INSERT INTO data_migrations VALUES('20241021125322');
INSERT INTO data_migrations VALUES('20241118155027');
INSERT INTO data_migrations VALUES('20250121164452');
CREATE TABLE IF NOT EXISTS "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY);
INSERT INTO schema_migrations VALUES('20210130201037');
INSERT INTO schema_migrations VALUES('20210130203243');
INSERT INTO schema_migrations VALUES('20210205230918');
INSERT INTO schema_migrations VALUES('20210210153744');
INSERT INTO schema_migrations VALUES('20210212143001');
INSERT INTO schema_migrations VALUES('20210212143002');
INSERT INTO schema_migrations VALUES('20210212143003');
INSERT INTO schema_migrations VALUES('20210212143004');
INSERT INTO schema_migrations VALUES('20210212143005');
INSERT INTO schema_migrations VALUES('20210212143006');
INSERT INTO schema_migrations VALUES('20210220204055');
INSERT INTO schema_migrations VALUES('20210225232756');
INSERT INTO schema_migrations VALUES('20210225232841');
INSERT INTO schema_migrations VALUES('20210301230017');
INSERT INTO schema_migrations VALUES('20210302161202');
INSERT INTO schema_migrations VALUES('20210314185822');
INSERT INTO schema_migrations VALUES('20210318202638');
INSERT INTO schema_migrations VALUES('20210321164508');
INSERT INTO schema_migrations VALUES('20210330215825');
INSERT INTO schema_migrations VALUES('20220105233138');
INSERT INTO schema_migrations VALUES('20220106220519');
INSERT INTO schema_migrations VALUES('20220612220115');
INSERT INTO schema_migrations VALUES('20220612220116');
INSERT INTO schema_migrations VALUES('20220612220117');
INSERT INTO schema_migrations VALUES('20220614210023');
INSERT INTO schema_migrations VALUES('20220614211256');
INSERT INTO schema_migrations VALUES('20220614213902');
INSERT INTO schema_migrations VALUES('20220617122809');
INSERT INTO schema_migrations VALUES('20220619174307');
INSERT INTO schema_migrations VALUES('20220626152444');
INSERT INTO schema_migrations VALUES('20220702202932');
INSERT INTO schema_migrations VALUES('20221128165903');
INSERT INTO schema_migrations VALUES('20221210001132');
INSERT INTO schema_migrations VALUES('20221219204414');
INSERT INTO schema_migrations VALUES('20221220223340');
INSERT INTO schema_migrations VALUES('20230202210000');
INSERT INTO schema_migrations VALUES('20230202210001');
INSERT INTO schema_migrations VALUES('20230203150000');
INSERT INTO schema_migrations VALUES('20230221180921');
INSERT INTO schema_migrations VALUES('20230222155910');
INSERT INTO schema_migrations VALUES('20230303150029');
INSERT INTO schema_migrations VALUES('20230305180823');
INSERT INTO schema_migrations VALUES('20230307215826');
INSERT INTO schema_migrations VALUES('20230308004237');
INSERT INTO schema_migrations VALUES('20230308005021');
INSERT INTO schema_migrations VALUES('20230313000000');
INSERT INTO schema_migrations VALUES('20230313000001');
INSERT INTO schema_migrations VALUES('20230316184012');
INSERT INTO schema_migrations VALUES('20230324000000');
INSERT INTO schema_migrations VALUES('20230615135601');
INSERT INTO schema_migrations VALUES('20230628195018');
INSERT INTO schema_migrations VALUES('20230707082403');
INSERT INTO schema_migrations VALUES('20230710102250');
INSERT INTO schema_migrations VALUES('20230711111009');
INSERT INTO schema_migrations VALUES('20240122114207');
INSERT INTO schema_migrations VALUES('20240127143358');
INSERT INTO schema_migrations VALUES('20240131134832');
INSERT INTO schema_migrations VALUES('20240208143319');
INSERT INTO schema_migrations VALUES('20240209125409');
INSERT INTO schema_migrations VALUES('20240228130246');
INSERT INTO schema_migrations VALUES('20240306095646');
INSERT INTO schema_migrations VALUES('20240319155251');
INSERT INTO schema_migrations VALUES('20240319155903');
INSERT INTO schema_migrations VALUES('20240322143621');
INSERT INTO schema_migrations VALUES('20240410221112');
INSERT INTO schema_migrations VALUES('20240410222922');
INSERT INTO schema_migrations VALUES('20240418112821');
INSERT INTO schema_migrations VALUES('20240423102250');
INSERT INTO schema_migrations VALUES('20240610120318');
INSERT INTO schema_migrations VALUES('20240614085913');
INSERT INTO schema_migrations VALUES('20240701142651');
INSERT INTO schema_migrations VALUES('20240703103707');
INSERT INTO schema_migrations VALUES('20240703160732');
INSERT INTO schema_migrations VALUES('20240727113215');
INSERT INTO schema_migrations VALUES('20240727113216');
INSERT INTO schema_migrations VALUES('20240727113217');
INSERT INTO schema_migrations VALUES('20240731165646');
INSERT INTO schema_migrations VALUES('20240827155630');
INSERT INTO schema_migrations VALUES('20240904151944');
INSERT INTO schema_migrations VALUES('20240924122004');
INSERT INTO schema_migrations VALUES('20240926162407');
INSERT INTO schema_migrations VALUES('20241004194445');
INSERT INTO schema_migrations VALUES('20241007182824');
INSERT INTO schema_migrations VALUES('20241009122540');
INSERT INTO schema_migrations VALUES('20241015090803');
INSERT INTO schema_migrations VALUES('20241017093301');
INSERT INTO schema_migrations VALUES('20241017113112');
INSERT INTO schema_migrations VALUES('20241021124608');
INSERT INTO schema_migrations VALUES('20241025110218');
INSERT INTO schema_migrations VALUES('20241105121830');
INSERT INTO schema_migrations VALUES('20241122121621');
INSERT INTO schema_migrations VALUES('20241128162213');
INSERT INTO schema_migrations VALUES('20241128162214');
INSERT INTO schema_migrations VALUES('20250114105808');
INSERT INTO schema_migrations VALUES('20250121105010');
INSERT INTO schema_migrations VALUES('20250122171731');
INSERT INTO schema_migrations VALUES('20250222000000');
INSERT INTO schema_migrations VALUES('20250305171530');
INSERT INTO schema_migrations VALUES('20250407160721');
INSERT INTO schema_migrations VALUES('20250407160722');
INSERT INTO schema_migrations VALUES('20250408111644');
INSERT INTO schema_migrations VALUES('20250408145956');
INSERT INTO schema_migrations VALUES('20250409120155');
INSERT INTO schema_migrations VALUES('20250409125753');
INSERT INTO schema_migrations VALUES('20250423094525');
INSERT INTO schema_migrations VALUES('20250425104619');
INSERT INTO schema_migrations VALUES('20250520111046');
INSERT INTO schema_migrations VALUES('20250609210440');
INSERT INTO schema_migrations VALUES('20250620141805');
INSERT INTO schema_migrations VALUES('20250621223410');
INSERT INTO schema_migrations VALUES('20250629212656');
CREATE TABLE IF NOT EXISTS "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
INSERT INTO ar_internal_metadata VALUES('environment','production','2025-07-25 10:52:31.380052','2025-07-25 10:52:31.380054');
CREATE TABLE IF NOT EXISTS "libraries" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "path" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "notes" varchar, "caption" varchar, "name" varchar, "tag_regex" text, "icon" text, "storage_service" varchar DEFAULT 'filesystem' NOT NULL, "s3_endpoint" varchar DEFAULT NULL, "s3_region" varchar DEFAULT NULL, "s3_bucket" varchar DEFAULT NULL, "s3_access_key_id" varchar DEFAULT NULL, "s3_secret_access_key" varchar DEFAULT NULL, "public_id" varchar, "s3_path_style" boolean DEFAULT 1 NOT NULL);
CREATE TABLE IF NOT EXISTS "tags" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "created_at" datetime, "updated_at" datetime, "taggings_count" integer DEFAULT 0);
CREATE TABLE IF NOT EXISTS "taggings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "tag_id" integer, "taggable_type" varchar, "taggable_id" integer, "tagger_type" varchar, "tagger_id" integer, "context" varchar(128), "created_at" datetime, CONSTRAINT "fk_rails_9fcd2e236b"
FOREIGN KEY ("tag_id")
REFERENCES "tags" ("id")
);
CREATE TABLE IF NOT EXISTS "links" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "url" varchar, "linkable_type" varchar, "linkable_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "var" varchar NOT NULL, "value" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
INSERT INTO settings VALUES(1,'default_library',replace('--- 2\n','\n',char(10)),'2025-07-25 10:58:00.004576','2025-07-28 13:30:03.381376');
INSERT INTO settings VALUES(2,'site_name',replace('--- XRForge\n','\n',char(10)),'2025-07-25 10:59:04.496016','2025-07-25 10:59:04.496016');
INSERT INTO settings VALUES(3,'site_tagline',replace('--- Selfsovereign XR Experiences based on 3D files & URLs\n','\n',char(10)),'2025-07-25 10:59:04.519264','2025-07-25 10:59:04.519264');
INSERT INTO settings VALUES(4,'theme','vapor','2025-07-25 10:59:04.522670','2025-07-28 13:47:54.690364');
INSERT INTO settings VALUES(5,'about',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.527612','2025-07-25 10:59:04.527612');
INSERT INTO settings VALUES(6,'rules',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.531378','2025-07-25 10:59:04.531378');
INSERT INTO settings VALUES(7,'support_link',replace('--- https://forgejo.isvery.ninja/coderofsalvation/xrforge\n','\n',char(10)),'2025-07-25 10:59:04.533678','2025-07-25 10:59:04.533678');
INSERT INTO settings VALUES(8,'site_icon',replace('--- ''''\n','\n',char(10)),'2025-07-25 10:59:04.536228','2025-07-25 14:19:06.192651');
CREATE TABLE IF NOT EXISTS "problems" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "problematic_type" varchar, "problematic_id" integer, "category" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "note" varchar DEFAULT NULL, "ignored" boolean DEFAULT 0 NOT NULL, "public_id" varchar, "in_progress" boolean DEFAULT 0 NOT NULL);
CREATE TABLE IF NOT EXISTS "favorites" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "favoritable_type" varchar NOT NULL, "favoritable_id" integer NOT NULL, "favoritor_type" varchar NOT NULL, "favoritor_id" integer NOT NULL, "scope" varchar DEFAULT 'printed' NOT NULL, "blocked" boolean DEFAULT 0 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "flipper_features" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "key" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "flipper_gates" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "feature_key" varchar NOT NULL, "key" varchar NOT NULL, "value" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "roles" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "resource_type" varchar, "resource_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
INSERT INTO roles VALUES(1,'administrator',NULL,NULL,'2025-07-25 10:52:35.066502','2025-07-25 10:52:35.066502');
INSERT INTO roles VALUES(2,'moderator',NULL,NULL,'2025-07-25 10:52:35.079751','2025-07-25 10:52:35.079751');
INSERT INTO roles VALUES(3,'contributor',NULL,NULL,'2025-07-25 10:52:35.081798','2025-07-25 10:52:35.081798');
INSERT INTO roles VALUES(4,'member',NULL,NULL,'2025-07-25 10:52:35.083068','2025-07-25 10:52:35.083068');
CREATE TABLE IF NOT EXISTS "users_roles" ("user_id" integer, "role_id" integer);
INSERT INTO users_roles VALUES(1,4);
INSERT INTO users_roles VALUES(1,1);
CREATE TABLE IF NOT EXISTS "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar DEFAULT '' NOT NULL, "encrypted_password" varchar DEFAULT '' NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "username" varchar NOT NULL, "pagination_settings" json DEFAULT '{"models":true,"creators":true,"collections":true,"per_page":12}', "renderer_settings" json DEFAULT '{"grid_width":200,"grid_depth":200,"show_grid":true,"enable_pan_zoom":false,"background_colour":"#000000","object_colour":"#ffffff","render_style":"original"}', "tag_cloud_settings" json DEFAULT '{"threshold":2,"heatmap":true,"keypair":true,"sorting":"frequency"}', "problem_settings" json DEFAULT '{"missing":"danger","empty":"info","nesting":"warning","inefficient":"info","duplicate":"warning","no_image":"silent","no_3d_model":"silent","non_manifold":"warning","inside_out":"warning","no_license":"silent","no_links":"silent","no_creator":"silent","no_tags":"silent"}', "file_list_settings" json DEFAULT '{"hide_presupported_versions":true}', "reset_password_token" varchar, "remember_created_at" datetime(6), "reset_password_sent_at" datetime(6), "interface_language" varchar, "failed_attempts" integer DEFAULT 0 NOT NULL, "locked_at" datetime(6), "auth_provider" varchar, "auth_uid" varchar, "sensitive_content_handling" varchar DEFAULT NULL, "public_id" varchar, "approved" boolean DEFAULT 1 NOT NULL, "quota" integer DEFAULT 1 NOT NULL, "quota_use_site_default" boolean DEFAULT 1 NOT NULL);
INSERT INTO users VALUES(1,'xrforge@localhost','$2a$12$u/j8LRzbPiJRHmi1eV/fvOXXiKxN2vBGtNd.Pt28w.wOnq3rnfpzO','2025-07-25 10:52:56.989975','2025-07-25 12:46:27.338917','xrforge','{"models":true,"creators":true,"collections":true,"per_page":12}','{"grid_width":200,"grid_depth":200,"show_grid":true,"enable_pan_zoom":false,"background_colour":"#000000","object_colour":"#ffffff","render_style":"original"}','{"threshold":2,"heatmap":true,"keypair":true,"sorting":"frequency"}','{"missing":"danger","empty":"info","nesting":"warning","inefficient":"info","duplicate":"warning","no_image":"silent","no_3d_model":"silent","non_manifold":"warning","inside_out":"warning","no_license":"silent","no_links":"silent","no_creator":"silent","no_tags":"silent"}','{"hide_presupported_versions":true}',NULL,'2025-07-25 12:46:27.325287',NULL,NULL,0,NULL,NULL,NULL,NULL,'71863vkppj6k',1,1,1);
CREATE TABLE IF NOT EXISTS "federails_followings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "actor_id" integer NOT NULL, "target_actor_id" integer NOT NULL, "status" integer DEFAULT 0, "federated_url" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "uuid" varchar DEFAULT NULL, CONSTRAINT "fk_rails_2e62338faa"
FOREIGN KEY ("actor_id")
REFERENCES "federails_actors" ("id")
, CONSTRAINT "fk_rails_4a2870c181"
FOREIGN KEY ("target_actor_id")
REFERENCES "federails_actors" ("id")
);
CREATE TABLE IF NOT EXISTS "federails_activities" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "entity_type" varchar NOT NULL, "entity_id" integer NOT NULL, "action" varchar NOT NULL, "actor_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "uuid" varchar DEFAULT NULL, CONSTRAINT "fk_rails_85ef6259df"
FOREIGN KEY ("actor_id")
REFERENCES "federails_actors" ("id")
);
CREATE TABLE IF NOT EXISTS "caber_relations" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "subject_type" varchar, "subject_id" integer, "permission" varchar, "object_type" varchar NOT NULL, "object_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "federails_moderation_reports" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "federated_url" varchar, "federails_actor_id" integer, "content" varchar, "object_type" varchar, "object_id" integer, "resolved_at" datetime(6), "resolution" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, CONSTRAINT "fk_rails_a5cda24d4c"
FOREIGN KEY ("federails_actor_id")
REFERENCES "federails_actors" ("id")
);
CREATE TABLE IF NOT EXISTS "federails_moderation_domain_blocks" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "domain" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "comments" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "public_id" varchar NOT NULL, "commenter_type" varchar, "commenter_id" integer, "commentable_type" varchar NOT NULL, "commentable_id" integer NOT NULL, "comment" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "system" boolean DEFAULT 0 NOT NULL, "sensitive" boolean DEFAULT 0 NOT NULL, "federated_url" varchar, "federails_actor_id" integer, CONSTRAINT "fk_rails_3a181ceff0"
FOREIGN KEY ("federails_actor_id")
REFERENCES "federails_actors" ("id")
);
CREATE TABLE IF NOT EXISTS "oauth_applications" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "uid" varchar NOT NULL, "secret" varchar NOT NULL, "redirect_uri" text, "scopes" varchar DEFAULT '' NOT NULL, "confidential" boolean DEFAULT 1 NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "owner_id" bigint, "owner_type" varchar);
CREATE TABLE IF NOT EXISTS "oauth_access_grants" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "resource_owner_id" integer NOT NULL, "application_id" integer NOT NULL, "token" varchar NOT NULL, "expires_in" integer NOT NULL, "redirect_uri" text NOT NULL, "scopes" varchar DEFAULT '' NOT NULL, "created_at" datetime(6) NOT NULL, "revoked_at" datetime(6), CONSTRAINT "fk_rails_b4b53e07b8"
FOREIGN KEY ("application_id")
REFERENCES "oauth_applications" ("id")
, CONSTRAINT "fk_rails_330c32d8d9"
FOREIGN KEY ("resource_owner_id")
REFERENCES "users" ("id")
);
CREATE TABLE IF NOT EXISTS "oauth_access_tokens" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "resource_owner_id" integer, "application_id" integer NOT NULL, "token" varchar NOT NULL, "refresh_token" varchar, "expires_in" integer, "scopes" varchar, "created_at" datetime(6) NOT NULL, "revoked_at" datetime(6), "previous_refresh_token" varchar DEFAULT '' NOT NULL, CONSTRAINT "fk_rails_732cb83ab7"
FOREIGN KEY ("application_id")
REFERENCES "oauth_applications" ("id")
, CONSTRAINT "fk_rails_ee63f25419"
FOREIGN KEY ("resource_owner_id")
REFERENCES "users" ("id")
);
CREATE TABLE IF NOT EXISTS "federails_actors" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "federated_url" varchar, "username" varchar, "server" varchar, "inbox_url" varchar, "outbox_url" varchar, "followers_url" varchar, "followings_url" varchar, "profile_url" varchar, "entity_id" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "entity_type" varchar DEFAULT NULL, "public_key" text, "private_key" text, "uuid" varchar, "extensions" json, "local" boolean DEFAULT 0 NOT NULL, "actor_type" varchar, "tombstoned_at" datetime(6));
INSERT INTO federails_actors VALUES(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,'2025-07-25 10:52:57.029315','2025-07-25 10:52:57.029315','User',NULL,NULL,'eb64d114-1bc7-4cb3-8be6-350d23ccfb3e',NULL,1,NULL,NULL);
CREATE TABLE IF NOT EXISTS "model_files" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "filename" varchar, "model_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "presupported" boolean DEFAULT 0 NOT NULL, "y_up" boolean DEFAULT 0 NOT NULL, "digest" varchar, "notes" text, "caption" text, "size" bigint, "presupported_version_id" integer, "attachment_data" json, "public_id" varchar, "filename_lower" varchar GENERATED ALWAYS AS (LOWER(filename)) STORED, "previewable" boolean DEFAULT 0 NOT NULL, CONSTRAINT "fk_rails_b5ac05b6e3"
FOREIGN KEY ("presupported_version_id")
REFERENCES "model_files" ("id")
, CONSTRAINT "fk_rails_8e378ff647"
FOREIGN KEY ("model_id")
REFERENCES "models" ("id")
);
CREATE TABLE IF NOT EXISTS "altcha_solutions" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "algorithm" varchar, "challenge" varchar, "salt" varchar, "signature" varchar, "number" integer, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
CREATE TABLE IF NOT EXISTS "models" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "path" varchar NOT NULL, "library_id" integer NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "preview_file_id" integer, "creator_id" integer, "notes" text, "caption" text, "collection_id" integer, "slug" varchar, "license" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "sensitive" boolean DEFAULT 0 NOT NULL, "indexable" varchar, "ai_indexable" varchar, CONSTRAINT "fk_rails_cdf016e15c"
FOREIGN KEY ("collection_id")
REFERENCES "collections" ("id")
, CONSTRAINT "fk_rails_aaa717f5bb"
FOREIGN KEY ("library_id")
REFERENCES "libraries" ("id")
, CONSTRAINT "fk_rails_3b8b50d3f3"
FOREIGN KEY ("creator_id")
REFERENCES "creators" ("id")
);
CREATE TABLE IF NOT EXISTS "creators" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar NOT NULL, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "notes" text, "caption" text, "slug" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "indexable" varchar, "ai_indexable" varchar);
CREATE TABLE IF NOT EXISTS "collections" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "notes" text, "caption" text, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL, "collection_id" integer, "slug" varchar, "public_id" varchar, "name_lower" varchar GENERATED ALWAYS AS (LOWER(name)) STORED, "creator_id" integer, "indexable" varchar, "ai_indexable" varchar, CONSTRAINT "fk_rails_63724415e9"
FOREIGN KEY ("collection_id")
REFERENCES "collections" ("id")
, CONSTRAINT "fk_rails_ab2fec83b3"
FOREIGN KEY ("creator_id")
REFERENCES "creators" ("id")
);
DELETE FROM sqlite_sequence;
INSERT INTO sqlite_sequence VALUES('taggings',0);
INSERT INTO sqlite_sequence VALUES('users',1);
INSERT INTO sqlite_sequence VALUES('comments',0);
INSERT INTO sqlite_sequence VALUES('oauth_access_grants',0);
INSERT INTO sqlite_sequence VALUES('oauth_access_tokens',0);
INSERT INTO sqlite_sequence VALUES('federails_actors',1);
INSERT INTO sqlite_sequence VALUES('model_files',0);
INSERT INTO sqlite_sequence VALUES('models',0);
INSERT INTO sqlite_sequence VALUES('creators',0);
INSERT INTO sqlite_sequence VALUES('collections',0);
INSERT INTO sqlite_sequence VALUES('roles',4);
INSERT INTO sqlite_sequence VALUES('libraries',2);
INSERT INTO sqlite_sequence VALUES('settings',8);
CREATE UNIQUE INDEX "index_tags_on_name" ON "tags" ("name");
CREATE UNIQUE INDEX "taggings_idx" ON "taggings" ("tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type");
CREATE INDEX "taggings_taggable_context_idx" ON "taggings" ("taggable_id", "taggable_type", "context");
CREATE INDEX "index_taggings_on_taggable_type" ON "taggings" ("taggable_type");
CREATE INDEX "index_taggings_on_context" ON "taggings" ("context");
CREATE INDEX "index_taggings_on_tagger_id_and_tagger_type" ON "taggings" ("tagger_id", "tagger_type");
CREATE INDEX "taggings_idy" ON "taggings" ("taggable_id", "taggable_type", "tagger_id", "context");
CREATE INDEX "index_links_on_linkable" ON "links" ("linkable_type", "linkable_id");
CREATE UNIQUE INDEX "index_settings_on_var" ON "settings" ("var");
CREATE INDEX "index_problems_on_problematic" ON "problems" ("problematic_type", "problematic_id");
CREATE INDEX "index_favorites_on_favoritor" ON "favorites" ("favoritor_type", "favoritor_id");
CREATE INDEX "index_favorites_on_scope" ON "favorites" ("scope");
CREATE INDEX "index_favorites_on_blocked" ON "favorites" ("blocked");
CREATE INDEX "fk_favorites" ON "favorites" ("favoritor_id", "favoritor_type");
CREATE INDEX "fk_favoritables" ON "favorites" ("favoritable_id", "favoritable_type");
CREATE UNIQUE INDEX "uniq_favorites__and_favoritables" ON "favorites" ("favoritable_type", "favoritable_id", "favoritor_type", "favoritor_id", "scope");
CREATE UNIQUE INDEX "index_problems_on_category_and_problematic_id_and_type" ON "problems" ("category", "problematic_id", "problematic_type");
CREATE UNIQUE INDEX "index_flipper_features_on_key" ON "flipper_features" ("key");
CREATE UNIQUE INDEX "index_flipper_gates_on_feature_key_and_key_and_value" ON "flipper_gates" ("feature_key", "key", "value");
CREATE INDEX "index_roles_on_resource" ON "roles" ("resource_type", "resource_id");
CREATE INDEX "index_users_roles_on_role_id" ON "users_roles" ("role_id");
CREATE INDEX "index_roles_on_name_and_resource_type_and_resource_id" ON "roles" ("name", "resource_type", "resource_id");
CREATE INDEX "index_users_roles_on_user_id_and_role_id" ON "users_roles" ("user_id", "role_id");
CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email");
CREATE UNIQUE INDEX "index_users_on_username" ON "users" ("username");
CREATE UNIQUE INDEX "index_users_on_reset_password_token" ON "users" ("reset_password_token");
CREATE INDEX "index_federails_followings_on_target_actor_id" ON "federails_followings" ("target_actor_id");
CREATE UNIQUE INDEX "index_federails_followings_on_actor_id_and_target_actor_id" ON "federails_followings" ("actor_id", "target_actor_id");
CREATE INDEX "index_federails_activities_on_entity" ON "federails_activities" ("entity_type", "entity_id");
CREATE INDEX "index_federails_activities_on_actor_id" ON "federails_activities" ("actor_id");
CREATE INDEX "index_caber_relations_on_subject" ON "caber_relations" ("subject_type", "subject_id");
CREATE INDEX "index_caber_relations_on_object" ON "caber_relations" ("object_type", "object_id");
CREATE UNIQUE INDEX "idx_on_subject_id_subject_type_object_id_object_typ_a279b094be" ON "caber_relations" ("subject_id", "subject_type", "object_id", "object_type");
CREATE INDEX "index_problems_on_public_id" ON "problems" ("public_id");
CREATE INDEX "index_libraries_on_public_id" ON "libraries" ("public_id");
CREATE UNIQUE INDEX "index_federails_activities_on_uuid" ON "federails_activities" ("uuid");
CREATE UNIQUE INDEX "index_federails_followings_on_uuid" ON "federails_followings" ("uuid");
CREATE INDEX "index_users_on_public_id" ON "users" ("public_id");
CREATE INDEX "index_users_on_approved" ON "users" ("approved");
CREATE INDEX "index_federails_moderation_reports_on_federails_actor_id" ON "federails_moderation_reports" ("federails_actor_id");
CREATE INDEX "index_federails_moderation_reports_on_object" ON "federails_moderation_reports" ("object_type", "object_id");
CREATE UNIQUE INDEX "index_federails_moderation_domain_blocks_on_domain" ON "federails_moderation_domain_blocks" ("domain");
CREATE UNIQUE INDEX "index_comments_on_public_id" ON "comments" ("public_id");
CREATE INDEX "index_comments_on_commenter" ON "comments" ("commenter_type", "commenter_id");
CREATE INDEX "index_comments_on_commentable" ON "comments" ("commentable_type", "commentable_id");
CREATE INDEX "index_comments_on_federails_actor_id" ON "comments" ("federails_actor_id");
CREATE UNIQUE INDEX "index_oauth_applications_on_uid" ON "oauth_applications" ("uid");
CREATE INDEX "index_oauth_access_grants_on_resource_owner_id" ON "oauth_access_grants" ("resource_owner_id");
CREATE INDEX "index_oauth_access_grants_on_application_id" ON "oauth_access_grants" ("application_id");
CREATE UNIQUE INDEX "index_oauth_access_grants_on_token" ON "oauth_access_grants" ("token");
CREATE INDEX "index_oauth_access_tokens_on_resource_owner_id" ON "oauth_access_tokens" ("resource_owner_id");
CREATE INDEX "index_oauth_access_tokens_on_application_id" ON "oauth_access_tokens" ("application_id");
CREATE UNIQUE INDEX "index_oauth_access_tokens_on_token" ON "oauth_access_tokens" ("token");
CREATE UNIQUE INDEX "index_oauth_access_tokens_on_refresh_token" ON "oauth_access_tokens" ("refresh_token");
CREATE INDEX "index_oauth_applications_on_owner_id_and_owner_type" ON "oauth_applications" ("owner_id", "owner_type");
CREATE UNIQUE INDEX "index_federails_actors_on_federated_url" ON "federails_actors" ("federated_url");
CREATE UNIQUE INDEX "index_federails_actors_on_entity" ON "federails_actors" ("entity_type", "entity_id");
CREATE UNIQUE INDEX "index_federails_actors_on_uuid" ON "federails_actors" ("uuid");
CREATE INDEX "index_model_files_on_model_id" ON "model_files" ("model_id");
CREATE INDEX "index_model_files_on_digest" ON "model_files" ("digest");
CREATE INDEX "index_model_files_on_presupported_version_id" ON "model_files" ("presupported_version_id");
CREATE UNIQUE INDEX "index_model_files_on_filename_and_model_id" ON "model_files" ("filename", "model_id");
CREATE INDEX "index_model_files_on_public_id" ON "model_files" ("public_id");
CREATE INDEX "index_model_files_on_filename_lower" ON "model_files" ("filename_lower");
CREATE INDEX "index_links_on_linkable_id_and_linkable_type_and_url" ON "links" ("linkable_id", "linkable_type", "url");
CREATE UNIQUE INDEX "index_altcha_solutions" ON "altcha_solutions" ("algorithm", "challenge", "salt", "signature", "number");
CREATE INDEX "index_models_on_library_id" ON "models" ("library_id");
CREATE INDEX "index_models_on_creator_id" ON "models" ("creator_id");
CREATE INDEX "index_models_on_preview_file_id" ON "models" ("preview_file_id");
CREATE INDEX "index_models_on_collection_id" ON "models" ("collection_id");
CREATE INDEX "index_models_on_slug" ON "models" ("slug");
CREATE UNIQUE INDEX "index_models_on_path_and_library_id" ON "models" ("path", "library_id");
CREATE INDEX "index_models_on_public_id" ON "models" ("public_id");
CREATE INDEX "index_models_on_name_lower" ON "models" ("name_lower");
CREATE UNIQUE INDEX "index_creators_on_name" ON "creators" ("name");
CREATE UNIQUE INDEX "index_creators_on_slug" ON "creators" ("slug");
CREATE INDEX "index_creators_on_public_id" ON "creators" ("public_id");
CREATE INDEX "index_creators_on_name_lower" ON "creators" ("name_lower");
CREATE INDEX "index_collections_on_collection_id" ON "collections" ("collection_id");
CREATE UNIQUE INDEX "index_collections_on_name" ON "collections" ("name");
CREATE UNIQUE INDEX "index_collections_on_slug" ON "collections" ("slug");
CREATE INDEX "index_collections_on_public_id" ON "collections" ("public_id");
CREATE INDEX "index_collections_on_name_lower" ON "collections" ("name_lower");
CREATE INDEX "index_collections_on_creator_id" ON "collections" ("creator_id");
CREATE INDEX "index_models_on_created_at" ON "models" ("created_at");
CREATE INDEX "index_models_on_updated_at" ON "models" ("updated_at");
CREATE INDEX "index_creators_on_created_at" ON "creators" ("created_at");
CREATE INDEX "index_creators_on_updated_at" ON "creators" ("updated_at");
CREATE INDEX "index_collections_on_created_at" ON "collections" ("created_at");
CREATE INDEX "index_collections_on_updated_at" ON "collections" ("updated_at");
COMMIT;

View file

@ -16,22 +16,34 @@ let
};
in
rec
{
foo = pkgs.dockerTools.buildImage {
xrforgeImage = pkgs.dockerTools.buildImage {
name = "xrforge";
tag = "latest";
created = "now";
fromImage = manyfoldImage;
# add nix pkgs + local files
copyToRoot = pkgs.buildEnv {
contents = pkgs.buildEnv {
name = "image-root";
pathsToLink = ["/manyfold" "/bin"];
paths = [pkgs.git ./..];
paths = [
pkgs.pkgsStatic.rsync
pkgs.pkgsStatic.sqlite
pkgs.pkgsStatic.rclone
pkgs.pkgsStatic.fuse3
./..
];
};
config = {
Cmd = ["${pkgsLinux.hello}/bin/hello" ];
Cmd = ["/init"];
# We substitute the /init entrypoing with our own wrapper
EntryPoint = ["/manyfold/cli/manyfold.sh" "boot"];
};
};
}

View file

@ -1,13 +1,32 @@
{ pkgs ? import <nixos-unstable> {} }:
pkgs.mkShell {
#let
# pkgs = import (builtins.fetchGit {
# name = "nixos-25.05";
# url = "https://github.com/nixos/nixpkgs/";
# ref = "refs/heads/nixos-unstable";
# rev = "ef99fa5c5ed624460217c31ac4271cfb5cb2502c";
# }) {};
{ pkgs ? import <nixos-unstable> {} } :
{
#pkgs = import (builtins.fetchGit {
# name = "nixos-25.05";
# url = "https://github.com/nixos/nixpkgs";
# rev = "11cb3517b3af6af300dd6c055aeda73c9bf52c48";
#}) {};
foo = pkgs.mkShell {
# nativeBuildInputs is usually what you want -- tools you need to run
nativeBuildInputs = with pkgs.buildPackages; [
monolith
nodejs_22
nixos-generators
qemu
#qemu
sqlite
];
@ -16,18 +35,27 @@
echo "available commands:"
echo ""
echo " # build 'xrforge' docker image"
echo " nix-build nix/docker.nix"
echo ""
echo "nix-build nix/xrforge.nix"
echo "nixos-generate -f <type> -c nix/server.nix # generate server-image for ~32 hyperscalers"
echo " # see https://mynixos.com/nixos-generators"
echo "example:"
echo " $ nixos-generate -f iso -c nix/server.nix
echo " # generate server-image for ~32 hyperscalers, see https://mynixos.com/nixos-generators"
echo " nixos-generate -f <type> -c nix/server.nix"
echo ""
echo " # use database of running container as default db for container"
echo " docker exec xrforge sqlite3 /config/manyfold.sqlite3 .dump > manyfold/manyfold.sql && nix-build nix/docker.nix"
echo ""
echo "examples:"
echo ""
echo " $ nixos-generate -f iso -c nix/server.nix"
echo " $ qemu-system-x86_64 -cdrom <isofile>" # test/run image
echo ""
echo " $ docker load < $(nix-build nix/docker.nix)"
echo " $ docker run -t hello-docker:y74sb4nrhxr975xs7h83izgm8z75x5fc"
echo " $ docker load < \$(nix-build nix/docker.nix)"
echo " $ docker run xrforge"
echo ""
'';
};
}