From 1d54d41f6bd569b170d0472b6b57e9e536bb1469 Mon Sep 17 00:00:00 2001
From: flashwave <me@flash.moe>
Date: Sun, 9 Feb 2025 19:58:09 +0000
Subject: [PATCH] No longer use random anonymous object for asset info.

---
 misuzu.php                              |  1 -
 src/AssetInfo.php                       | 24 ++++++++++++++++++++++++
 src/Misuzu.php                          |  5 ++++-
 src/MisuzuContext.php                   | 14 +++++---------
 src/Redirects/SocialRedirectsRoutes.php | 12 ++++--------
 src/TemplatingExtension.php             | 22 ++++++----------------
 6 files changed, 43 insertions(+), 35 deletions(-)
 create mode 100644 src/AssetInfo.php

diff --git a/misuzu.php b/misuzu.php
index d6e42fa6..6e1bf829 100644
--- a/misuzu.php
+++ b/misuzu.php
@@ -12,7 +12,6 @@ define('MSZ_SOURCE', MSZ_ROOT . '/src');
 define('MSZ_CONFIG', MSZ_ROOT . '/config');
 define('MSZ_TEMPLATES', MSZ_ROOT . '/templates');
 define('MSZ_MIGRATIONS', MSZ_ROOT . '/database');
-define('MSZ_ASSETS', MSZ_ROOT . '/assets');
 
 require_once MSZ_ROOT . '/vendor/autoload.php';
 
diff --git a/src/AssetInfo.php b/src/AssetInfo.php
new file mode 100644
index 00000000..442b58d4
--- /dev/null
+++ b/src/AssetInfo.php
@@ -0,0 +1,24 @@
+<?php
+namespace Misuzu;
+
+class AssetInfo {
+    public const string CURRENT_PATH = Misuzu::PATH_ASSETS . DIRECTORY_SEPARATOR . 'current.json';
+
+    /** @var array<string, string> */
+    private array $assets;
+
+    /** @param string|array<string, string> $pathOrAssets */
+    public function __construct(string|array $pathOrAssets = []) {
+        if(is_string($pathOrAssets) && is_file($pathOrAssets)) {
+            $data = file_get_contents($pathOrAssets);
+            if($data !== false)
+                $pathOrAssets = json_decode($data, true);
+        }
+
+        $this->assets = is_array($pathOrAssets) && !array_is_list($pathOrAssets) ? $pathOrAssets : [];
+    }
+
+    public function getAssetUrl(string $name): string {
+        return array_key_exists($name, $this->assets) ? $this->assets[$name] : '';
+    }
+}
diff --git a/src/Misuzu.php b/src/Misuzu.php
index d36cbf64..c4787685 100644
--- a/src/Misuzu.php
+++ b/src/Misuzu.php
@@ -2,7 +2,10 @@
 namespace Misuzu;
 
 final class Misuzu {
-    public const string PATH_VERSION = MSZ_ROOT . DIRECTORY_SEPARATOR . 'VERSION';
+    public const string PATH_SOURCE = __DIR__;
+    public const string PATH_ROOT = self::PATH_SOURCE . DIRECTORY_SEPARATOR . '..';
+    public const string PATH_ASSETS = self::PATH_ROOT . DIRECTORY_SEPARATOR . 'assets';
+    public const string PATH_VERSION = self::PATH_ROOT . DIRECTORY_SEPARATOR . 'VERSION';
 
     public static function version(): string {
         if(!is_file(self::PATH_VERSION))
diff --git a/src/MisuzuContext.php b/src/MisuzuContext.php
index b568d9ff..6a79c25b 100644
--- a/src/MisuzuContext.php
+++ b/src/MisuzuContext.php
@@ -41,6 +41,7 @@ class MisuzuContext {
     public private(set) Perms\PermissionsData $perms;
     public private(set) Auth\AuthInfo $authInfo;
     public private(set) SiteInfo $siteInfo;
+    public private(set) AssetInfo $assetInfo;
 
     // this probably shouldn't be available
     public private(set) UrlRegistry $urls;
@@ -49,6 +50,7 @@ class MisuzuContext {
         public private(set) Config $env
     ) {
         $this->deps = new Dependencies;
+        $this->deps->register($this);
         $this->deps->register($this->deps);
         $this->deps->register($this->env);
 
@@ -60,6 +62,7 @@ class MisuzuContext {
         $this->deps->register($this->perms = $this->deps->constructLazy(Perms\PermissionsData::class));
         $this->deps->register($this->authInfo = $this->deps->constructLazy(Auth\AuthInfo::class));
         $this->deps->register($this->siteInfo = $this->deps->constructLazy(SiteInfo::class, config: $this->config->scopeTo('site')));
+        $this->deps->register($this->assetInfo = $this->deps->constructLazy(AssetInfo::class, pathOrAssets: AssetInfo::CURRENT_PATH));
 
         $this->deps->register($this->appsCtx = $this->deps->constructLazy(Apps\AppsContext::class));
         $this->deps->register($this->authCtx = $this->deps->constructLazy(Auth\AuthContext::class, config: $this->config->scopeTo('auth')));
@@ -104,10 +107,6 @@ class MisuzuContext {
         return $this->hasManageAccess;
     }
 
-    public function getWebAssetInfo(): object {
-        return json_decode(file_get_contents(MSZ_ASSETS . '/current.json'));
-    }
-
     private ?string $chatUrl = null;
     public function getChatURL(): string {
         $this->chatUrl ??= $this->config->getString('sockChat.chatPath.normal');
@@ -132,7 +131,7 @@ class MisuzuContext {
             cache: $isDebug || !$cache ? null : ['Misuzu', GitInfo::hash(true)],
             debug: $isDebug
         );
-        $this->templating->addExtension(new TemplatingExtension($this));
+        $this->templating->addExtension($this->deps->construct(TemplatingExtension::class));
         $this->templating->addGlobal('globals', $globals);
 
         Template::init($this->templating);
@@ -212,10 +211,7 @@ class MisuzuContext {
         $routingCtx->register($this->deps->constructLazy(Redirects\LandingRedirectsRoutes::class));
         $routingCtx->register($this->deps->constructLazy(Redirects\AliasRedirectsRoutes::class));
         $routingCtx->register($this->deps->constructLazy(Redirects\IncrementalRedirectsRoutes::class));
-        $routingCtx->register($this->deps->constructLazy(
-            Redirects\SocialRedirectsRoutes::class,
-            getWebAssetInfo: $this->getWebAssetInfo(...)
-        ));
+        $routingCtx->register($this->deps->constructLazy(Redirects\SocialRedirectsRoutes::class));
         $routingCtx->register($this->deps->constructLazy(Redirects\NamedRedirectsRoutes::class));
     }
 }
diff --git a/src/Redirects/SocialRedirectsRoutes.php b/src/Redirects/SocialRedirectsRoutes.php
index 5cfaaabc..34830d4b 100644
--- a/src/Redirects/SocialRedirectsRoutes.php
+++ b/src/Redirects/SocialRedirectsRoutes.php
@@ -1,25 +1,21 @@
 <?php
 namespace Misuzu\Redirects;
 
-use InvalidArgumentException;
 use Index\Config\Config;
 use Index\Http\{HttpRequest,HttpResponseBuilder};
 use Index\Http\Routing\{HttpGet,RouteHandler,RouteHandlerCommon};
+use Misuzu\AssetInfo;
 
 class SocialRedirectsRoutes implements RouteHandler {
     use RouteHandlerCommon;
 
     private Config $config;
 
-    /** @param callable(): object $getWebAssetInfo */
     public function __construct(
         RedirectsContext $redirectsCtx,
-        private $getWebAssetInfo
+        private AssetInfo $assetInfo
     ) {
         $this->config = $redirectsCtx->config->scopeTo('social');
-        if(!is_callable($getWebAssetInfo))
-            throw new InvalidArgumentException('$getWebAssetInfo must be callable');
-        $this->getWebAssetInfo = $getWebAssetInfo;
     }
 
     #[HttpGet('/bsky/((did:[a-z0-9]+:[A-Za-z0-9.\-_:%]+)|(([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])))')]
@@ -52,7 +48,7 @@ class SocialRedirectsRoutes implements RouteHandler {
         }
 
         $handle = rawurlencode($handle);
-        $script = ($this->getWebAssetInfo)()->{'redir-bsky.js'} ?? '';
+        $script = $this->assetInfo->getAssetUrl('redir-bsky.js');
 
         return <<<HTML
         <!doctype html>
@@ -68,7 +64,7 @@ class SocialRedirectsRoutes implements RouteHandler {
     public function getFediverseRedirect(HttpResponseBuilder $response, HttpRequest $request, string $userName, string $instance): string {
         $userName = rawurlencode($userName);
         $instance = rawurlencode($instance);
-        $script = ($this->getWebAssetInfo)()->{'redir-fedi.js'} ?? '';
+        $script = $this->assetInfo->getAssetUrl('redir-fedi.js');
 
         return <<<HTML
         <!doctype html>
diff --git a/src/TemplatingExtension.php b/src/TemplatingExtension.php
index d136773b..c320fcac 100644
--- a/src/TemplatingExtension.php
+++ b/src/TemplatingExtension.php
@@ -3,21 +3,15 @@ namespace Misuzu;
 
 use DateTimeInterface;
 use Carbon\CarbonImmutable;
-use Misuzu\MisuzuContext;
-use Misuzu\Tools;
 use Misuzu\Parsers\{Parsers,TextFormat};
+use Twig\{TwigFilter,TwigFunction};
 use Twig\Extension\AbstractExtension;
-use Twig\TwigFilter;
-use Twig\TwigFunction;
 
 final class TemplatingExtension extends AbstractExtension {
-    private MisuzuContext $ctx;
-    private object $assets;
-
-    public function __construct(MisuzuContext $ctx) {
-        $this->ctx = $ctx;
-        $this->assets = $ctx->getWebAssetInfo();
-    }
+    public function __construct(
+        private MisuzuContext $ctx,
+        private AssetInfo $assetInfo
+    ) {}
 
     public function getFilters() {
         return [
@@ -30,7 +24,7 @@ final class TemplatingExtension extends AbstractExtension {
 
     public function getFunctions() {
         return [
-            new TwigFunction('asset', $this->getAssetPath(...)),
+            new TwigFunction('asset', $this->assetInfo->getAssetUrl(...)),
             new TwigFunction('url', $this->ctx->urls->format(...)),
             new TwigFunction('csrf_available', CSRF::available(...)),
             new TwigFunction('csrf_token', CSRF::token(...)),
@@ -52,10 +46,6 @@ final class TemplatingExtension extends AbstractExtension {
         ];
     }
 
-    public function getAssetPath(string $name): string {
-        return $this->assets->{$name} ?? '';
-    }
-
     public function timeFormat(DateTimeInterface|string|int|null $dateTime): string {
         if($dateTime === null)
             return 'never';