@@ -98,7 +98,7 @@ let
9898 obelisk-cliapp = self.callCabal2nix "obelisk-cliapp" (cleanSource ./lib/cliapp) {};
9999 obelisk-command = (self.callCabal2nix "obelisk-command" (cleanSource ./lib/command) {});
100100 obelisk-executable-config = executableConfig.haskellPackage self;
101− obelisk-executable-config-inject = executableConfig.platforms.web.inject self; # TODO handle platforms.{ios,android}
101+ obelisk-executable-config-inject = executableConfig.platforms.web.inject self;
102102 obelisk-frontend = self.callCabal2nix "obelisk-frontend" (cleanSource ./lib/frontend) {};
103103 obelisk-migration = self.callCabal2nix "obelisk-migration" (cleanSource ./lib/migration) {};
104104 obelisk-run = self.callCabal2nix "obelisk-run" (cleanSource ./lib/run) {};
@@ -120,8 +120,8 @@ rec {
120120 path = reflex-platform.filterGit ./.;
121121 obelisk = ghcObelisk;
122122 commandWithMigration = ghcObelisk.obelisk-command.overrideAttrs (drv: {
123− postInstall = (drv.postInstall or "") +
124− ''cp -r ${./migration} $out/migration;'';
123+ postInstall = (drv.postInstall or "") +
124+ ''cp -r ${./migration} $out/migration;'';
125125 });
126126 command = pkgs.runCommand commandWithMigration.name { nativeBuildInputs = [pkgs.makeWrapper]; } ''
127127 mkdir -p "$out/bin"
@@ -160,13 +160,80 @@ rec {
160160 '';
161161
162162 compressedJs = frontend: pkgs.runCommand "compressedJs" { buildInputs = [ pkgs.closurecompiler ]; } ''
163− mkdir $out
164− cd $out
165− ln -s "${justStaticExecutables frontend}/bin/frontend.jsexe/all.js" all.unminified.js
166− closure-compiler --externs "${reflex-platform.ghcjsExternsJs}" -O ADVANCED --jscomp_warning=checkVars --create_source_map="all.js.map" --source_map_format=V3 --js_output_file="all.js" all.unminified.js
167− echo "//# sourceMappingURL=all.js.map" >> all.js
163+ mkdir $out
164+ cd $out
165+ ln -s "${justStaticExecutables frontend}/bin/frontend.jsexe/all.js" all.unminified.js
166+ closure-compiler --externs "${reflex-platform.ghcjsExternsJs}" -O ADVANCED --jscomp_warning=checkVars --create_source_map="all.js.map" --source_map_format=V3 --js_output_file="all.js" all.unminified.js
167+ echo "//# sourceMappingURL=all.js.map" >> all.js
168168 '';
169169
170+ serverModules = {
171+ mkBaseEc2 = { hostName, routeHost, enableHttps, adminEmail, ... }: {...}: {
172+ imports = [
173+ (pkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
174+ ];
175+ networking = {
176+ inherit hostName;
177+ firewall.allowedTCPPorts = if enableHttps then [ 80 443 ] else [ 80 ];
178+ };
179+ security.acme.certs = if enableHttps then {
180+ "${routeHost}".email = adminEmail;
181+ } else {};
182+ ec2.hvm = true;
183+ };
184+
185+ mkObeliskApp =
186+ { exe
187+ , routeHost
188+ , enableHttps
189+ , name ? "backend"
190+ , user ? name
191+ , group ? user
192+ , baseUrl ? "/"
193+ , internalPort ? 8000
194+ , backendArgs ? ""
195+ , ...
196+ }: {...}: {
197+ services.nginx = {
198+ enable = true;
199+ virtualHosts."${routeHost}" = {
200+ enableACME = enableHttps;
201+ forceSSL = enableHttps;
202+ locations.${baseUrl} = {
203+ proxyPass = "http://localhost:" + toString internalPort;
204+ };
205+ };
206+ };
207+ systemd.services.${name} = {
208+ wantedBy = [ "multi-user.target" ];
209+ after = [ "network.target" ];
210+ restartIfChanged = true;
211+ script = ''
212+ ln -sft . '${exe}'/*
213+ mkdir -p log
214+ exec ./backend --port=${toString internalPort} ${backendArgs} >>backend.out 2>>backend.err </dev/null
215+ '';
216+ serviceConfig = {
217+ User = user;
218+ KillMode = "process";
219+ WorkingDirectory = "~";
220+ Restart = "always";
221+ RestartSec = 5;
222+ };
223+ };
224+ users = {
225+ users.${user} = {
226+ description = "${user} service";
227+ home = "/var/lib/${user}";
228+ createHome = true;
229+ isSystemUser = true;
230+ group = group;
231+ };
232+ groups.${group} = {};
233+ };
234+ };
235+ };
236+
170237 serverExe = backend: frontend: assets: config:
171238 pkgs.runCommand "serverExe" {} ''
172239 mkdir $out
@@ -177,58 +244,16 @@ rec {
177244 ln -s ${mkAssets (compressedJs frontend)} $out/frontend.jsexe.assets
178245 '';
179246
180− server = { exe, hostName, adminEmail, routeHost, enableHttps, ... }:
181− let system = "x86_64-linux";
182− nixos = import (pkgs.path + /nixos);
183− backendPort = 8000;
247+ server = { exe, hostName, adminEmail, routeHost, enableHttps }@args:
248+ let
249+ nixos = import (pkgs.path + /nixos);
184250 in nixos {
185− inherit system;
186− configuration = args: {
251+ system = "x86_64-linux";
252+ configuration = {
187253 imports = [
188− (pkgs.path + /nixos/modules/virtualisation/amazon-image.nix)
254+ (serverModules.mkBaseEc2 args)
255+ (serverModules.mkObeliskApp args)
189256 ];
190− networking = {
191− inherit hostName;
192− firewall.allowedTCPPorts = if enableHttps then [ 80 443 ] else [ 80 ];
193− };
194− services.nginx = {
195− enable = true;
196− virtualHosts."${routeHost}" = {
197− enableACME = enableHttps;
198− forceSSL = enableHttps;
199− locations."/" = {
200− proxyPass = "http://127.0.0.1:" + toString backendPort;
201− };
202− };
203− };
204− security.acme.certs = if enableHttps then {
205− "${routeHost}".email = adminEmail;
206− } else { };
207− systemd.services.backend = {
208− wantedBy = [ "multi-user.target" ];
209− after = [ "network.target" ];
210− restartIfChanged = true;
211− script = ''
212− ln -sft . "${exe}"/*
213− mkdir -p log
214− exec ./backend >>backend.out 2>>backend.err </dev/null
215− '';
216− serviceConfig = {
217− User = "backend";
218− KillMode = "process";
219− WorkingDirectory = "~";
220− Restart = "always";
221− RestartSec = 5;
222− };
223− };
224− users.extraUsers.backend = {
225− description = "backend service";
226− home = "/var/lib/backend";
227− createHome = true;
228− isSystemUser = true;
229− group = "backend";
230− };
231− ec2.hvm = true;
232257 };
233258 };
234259
@@ -264,6 +289,12 @@ rec {
264289 ${backendName} = addBuildDepend super.${backendName} self.obelisk-run;
265290 };
266291 totalOverrides = composeExtensions (composeExtensions defaultHaskellOverrides projectOverrides) overrides;
292+ inherit (nixpkgs) lib;
293+ inherit (lib.strings) hasPrefix;
294+ privateConfigDirs = ["config/backend"];
295+ injectableConfig = builtins.filterSource (path: _:
296+ !(lib.lists.any (x: hasPrefix (toString base + "/" + toString x) (toString path)) privateConfigDirs)
297+ ) configPath;
267298 in {
268299 inherit shellToolOverrides tools withHoogle;
269300 overrides = totalOverrides;
@@ -282,13 +313,15 @@ rec {
282313 android = {
283314 ${if android == null then null else frontendName} = {
284315 executableName = "frontend";
285− ${if builtins.pathExists staticPath then "assets" else null} = processedStatic.symlinked;
316+ ${if builtins.pathExists staticPath then "assets" else null} =
317+ executableConfig.platforms.android.inject injectableConfig processedStatic.symlinked;
286318 } // android;
287319 };
288320 ios = {
289321 ${if ios == null then null else frontendName} = {
290322 executableName = "frontend";
291− ${if builtins.pathExists staticPath then "staticSrc" else null} = processedStatic.symlinked;
323+ ${if builtins.pathExists staticPath then "staticSrc" else null} =
324+ executableConfig.platforms.ios.inject injectableConfig processedStatic.symlinked;
292325 } // ios;
293326 };
294327 };