diff --git a/appview/auth/auth.go b/appview/auth/auth.go index f935ff8b..7e8a3753 100644 --- a/appview/auth/auth.go +++ b/appview/auth/auth.go @@ -27,8 +27,8 @@ type AtSessionRefresh struct { PDSEndpoint string } -func Make() (*Auth, error) { - store := sessions.NewCookieStore([]byte(appview.SessionCookieSecret)) +func Make(secret string) (*Auth, error) { + store := sessions.NewCookieStore([]byte(secret)) return &Auth{store}, nil } diff --git a/appview/config.go b/appview/config.go new file mode 100644 index 00000000..ff8ac293 --- /dev/null +++ b/appview/config.go @@ -0,0 +1,24 @@ +package appview + +import ( + "context" + + "github.com/sethvargo/go-envconfig" +) + +type Config struct { + CookieSecret string `env:"TANGLED_COOKIE_SECRET, default=00000000000000000000000000000000"` + Hostname string `env:"TANGLED_HOSTNAME, default=0.0.0.0"` + Port string `env:"TANGLED_PORT, default=3000"` + DbPath string `env:"TANGLED_DB_PATH, default=appview.db"` +} + +func LoadConfig(ctx context.Context) (*Config, error) { + var cfg Config + err := envconfig.Process(ctx, &cfg) + if err != nil { + return nil, err + } + + return &cfg, nil +} diff --git a/appview/consts.go b/appview/consts.go index 594ec549..3a15eb1b 100644 --- a/appview/consts.go +++ b/appview/consts.go @@ -1,7 +1,6 @@ package appview const ( - SessionCookieSecret = "TODO_CHANGE_ME" SessionName = "appview-session" SessionHandle = "handle" SessionDid = "did" @@ -10,5 +9,4 @@ const ( SessionRefreshJwt = "refreshJwt" SessionExpiry = "expiry" SessionAuthenticated = "authenticated" - SqliteDbPath = "appview.db" ) diff --git a/appview/state/state.go b/appview/state/state.go index 6501484a..6372af7e 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -34,20 +34,21 @@ type State struct { pages *pages.Pages resolver *appview.Resolver jc *jetstream.JetstreamClient + config *appview.Config } -func Make() (*State, error) { - db, err := db.Make(appview.SqliteDbPath) +func Make(config *appview.Config) (*State, error) { + db, err := db.Make(config.DbPath) if err != nil { return nil, err } - auth, err := auth.Make() + auth, err := auth.Make(config.CookieSecret) if err != nil { return nil, err } - enforcer, err := rbac.NewEnforcer(appview.SqliteDbPath) + enforcer, err := rbac.NewEnforcer(config.DbPath) if err != nil { return nil, err } @@ -75,6 +76,7 @@ func Make() (*State, error) { pgs, resolver, jc, + config, } return state, nil diff --git a/cmd/appview/main.go b/cmd/appview/main.go index 4cafba22..fe3d835b 100644 --- a/cmd/appview/main.go +++ b/cmd/appview/main.go @@ -1,26 +1,33 @@ package main import ( + "context" "fmt" "log" "log/slog" "net/http" "os" + "github.com/sotangled/tangled/appview" "github.com/sotangled/tangled/appview/state" ) func main() { - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil))) - state, err := state.Make() + c, err := appview.LoadConfig(context.Background()) + if err != nil { + log.Println("failed to load config", "error", err) + return + } + + state, err := state.Make(c) if err != nil { log.Fatal(err) } - addr := fmt.Sprintf("%s:%d", "localhost", 3000) + addr := fmt.Sprintf("%s:%s", c.Hostname, c.Port) log.Println("starting server on", addr) log.Println(http.ListenAndServe(addr, state.Router())) diff --git a/flake.nix b/flake.nix index 624212c8..d6e615e8 100644 --- a/flake.nix +++ b/flake.nix @@ -43,7 +43,18 @@ }); inherit (gitignore.lib) gitignoreSource; in { - overlays.default = final: prev: { + overlays.default = final: prev: let + goModHash = "sha256-ywhhGrv8KNqy9tCMCnA1PU/RQ/+0Xyitej1L48TcFvI="; + buildCmdPackage = name: + final.buildGoModule { + pname = name; + version = "0.1.0"; + src = gitignoreSource ./.; + subPackages = ["cmd/${name}"]; + vendorHash = goModHash; + env.CGO_ENABLED = 0; + }; + in { indigo-lexgen = with final; final.buildGoModule { pname = "indigo-lexgen"; @@ -68,37 +79,22 @@ ''; doCheck = false; subPackages = ["cmd/appview"]; - vendorHash = "sha256-ywhhGrv8KNqy9tCMCnA1PU/RQ/+0Xyitej1L48TcFvI="; + vendorHash = goModHash; env.CGO_ENABLED = 1; stdenv = pkgsStatic.stdenv; }; + knotserver = with final; final.pkgsStatic.buildGoModule { pname = "knotserver"; version = "0.1.0"; src = gitignoreSource ./.; subPackages = ["cmd/knotserver"]; - vendorHash = "sha256-ywhhGrv8KNqy9tCMCnA1PU/RQ/+0Xyitej1L48TcFvI="; + vendorHash = goModHash; env.CGO_ENABLED = 1; }; - repoguard = with final; - final.pkgsStatic.buildGoModule { - pname = "repoguard"; - version = "0.1.0"; - src = gitignoreSource ./.; - subPackages = ["cmd/repoguard"]; - vendorHash = "sha256-ywhhGrv8KNqy9tCMCnA1PU/RQ/+0Xyitej1L48TcFvI="; - env.CGO_ENABLED = 0; - }; - keyfetch = with final; - final.pkgsStatic.buildGoModule { - pname = "keyfetch"; - version = "0.1.0"; - src = gitignoreSource ./.; - subPackages = ["cmd/keyfetch"]; - vendorHash = "sha256-ywhhGrv8KNqy9tCMCnA1PU/RQ/+0Xyitej1L48TcFvI="; - env.CGO_ENABLED = 0; - }; + repoguard = buildCmdPackage "repoguard"; + keyfetch = buildCmdPackage "keyfetch"; }; packages = forAllSystems (system: { inherit (nixpkgsFor."${system}") indigo-lexgen appview knotserver repoguard keyfetch; @@ -123,10 +119,10 @@ pkgs.tailwindcss ]; shellHook = '' - cp -f ${htmx-src} appview/pages/static/htmx.min.js - cp -f ${lucide-src} appview/pages/static/lucide.min.js - cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ - cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ + cp -f ${htmx-src} appview/pages/static/htmx.min.js + cp -f ${lucide-src} appview/pages/static/lucide.min.js + cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ + cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ ''; }; }); @@ -150,5 +146,54 @@ program = ''${air-watcher "knotserver"}/bin/run''; }; }); + + nixosModules.default = { + config, + pkgs, + lib, + ... + }: + with lib; { + options = { + services.tangled-appview = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable tangled appview"; + }; + port = mkOption { + type = types.int; + default = 3000; + description = "Port to run the appview on"; + }; + cookie_secret = mkOption { + type = types.str; + default = "00000000000000000000000000000000"; + description = "Cookie secret"; + }; + }; + }; + + config = mkIf config.services.tangled-appview.enable { + nixpkgs.overlays = [self.overlays.default]; + systemd.services.tangled-appview = { + description = "tangled appview service"; + wantedBy = ["multi-user.target"]; + + serviceConfig = { + ListenStream = "0.0.0.0:${toString config.services.tangled-appview.port}"; + ExecStart = "${pkgs.tangled-appview}/bin/tangled-appview"; + Restart = "always"; + }; + + environment = { + TANGLED_PORT = "${toString config.services.tangled-appview.port}"; + TANGLED_HOST = "localhost"; + TANGLED_DB_PATH = "appview.db"; + TANGLED_COOKIE_SECRET = config.services.tangled-appview.cookie_secret; + }; + }; + }; + }; }; }