ModuleStoreUtil.php 9.9 KB
Newer Older
S
develop  
server 已提交
1 2 3 4 5 6 7
<?php


namespace Module\ModuleStore\Util;


use Chumper\Zipper\Zipper;
ModStart's avatar
develop  
ModStart 已提交
8
use Illuminate\Support\Facades\Cache;
S
develop  
server 已提交
9
use ModStart\Core\Exception\BizException;
ModStart's avatar
develop  
ModStart 已提交
10
use ModStart\Core\Input\InputPackage;
S
develop  
server 已提交
11 12 13
use ModStart\Core\Input\Response;
use ModStart\Core\Util\CurlUtil;
use ModStart\Core\Util\FileUtil;
S
develop  
server 已提交
14 15
use ModStart\Core\Util\VersionUtil;
use ModStart\ModStart;
S
develop  
server 已提交
16 17 18 19 20 21 22 23
use ModStart\Module\ModuleManager;

class ModuleStoreUtil
{
    const REMOTE_BASE = 'https://modstart.com';

    public static function remoteModuleData()
    {
ModStart's avatar
develop  
ModStart 已提交
24 25 26 27 28 29 30
        $input = InputPackage::buildFromInput();
        $memberUserId = $input->getInteger('memberUserId');
        $apiToken = $input->getTrimString('apiToken');
        return Cache::remember('ModuleStore_Modules:' . $memberUserId, 60, function () use ($apiToken) {
            return CurlUtil::getJSONData(self::REMOTE_BASE . '/api/store/module', [
                'api_token' => $apiToken,
            ]);
ModStart's avatar
develop  
ModStart 已提交
31
        });
S
develop  
server 已提交
32 33 34 35
    }

    public static function all()
    {
S
develop  
server 已提交
36 37 38
        $storeConfig = [
            'disable' => config('env.MS_MODULE_STORE_DISABLE', false),
        ];
ModStart's avatar
develop  
ModStart 已提交
39
        $result = self::remoteModuleData();
S
develop  
server 已提交
40
        $categories = [];
ModStart's avatar
develop  
ModStart 已提交
41 42 43 44 45 46
        if (!empty($result['data']['categories'])) {
            $categories = $result['data']['categories'];
        }
        $types = [];
        if (!empty($result['data']['types'])) {
            $types = $result['data']['types'];
S
develop  
server 已提交
47 48
        }
        $modules = [];
ModStart's avatar
develop  
ModStart 已提交
49 50
        if (!empty($result['data']['modules'])) {
            foreach ($result['data']['modules'] as $remote) {
S
develop  
server 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
                $remote['_isLocal'] = false;
                $remote['_isInstalled'] = false;
                $remote['_isEnabled'] = false;
                $remote['_localVersion'] = null;
                $remote['_isSystem'] = false;
                $remote['_hasConfig'] = false;
                $modules[$remote['name']] = $remote;
            }
        }
        foreach (ModuleManager::listModules() as $m => $config) {
            $info = ModuleManager::getModuleBasic($m);
            if (isset($modules[$m])) {
                $modules[$m]['_isInstalled'] = $config['isInstalled'];
                $modules[$m]['_isEnabled'] = $config['enable'];
                $modules[$m]['_localVersion'] = $info['version'];
                $modules[$m]['_isSystem'] = $config['isSystem'];
                $modules[$m]['_hasConfig'] = !empty($info['config']);
            } else {
                $modules[$m] = [
                    'id' => 0,
                    'name' => $m,
                    'title' => $info['title'],
                    'cover' => null,
                    'categoryId' => null,
                    'latestVersion' => $info['version'],
                    'releases' => [],
                    'url' => null,
                    'isFee' => false,
                    'priceSuper' => null,
                    'priceSuperEnable' => false,
                    'priceYear' => null,
                    'priceYearEnable' => false,
                    'description' => $info['description'],
                    '_isLocal' => true,
                    '_isInstalled' => $config['isInstalled'],
                    '_isEnabled' => $config['enable'],
                    '_localVersion' => $info['version'],
                    '_isSystem' => $config['isSystem'],
                    '_hasConfig' => !empty($info['config']),
                ];
            }
        }
        return [
S
develop  
server 已提交
94
            'storeConfig' => $storeConfig,
S
develop  
server 已提交
95
            'categories' => $categories,
ModStart's avatar
develop  
ModStart 已提交
96
            'types' => $types,
S
develop  
server 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110
            'modules' => array_values($modules),
        ];
    }

    private static function baseRequest($api, $data, $token)
    {
        return CurlUtil::postJSONBody(self::REMOTE_BASE . $api, $data, [
            'header' => [
                'api-token' => $token,
                'X-Requested-With' => 'XMLHttpRequest',
            ]
        ]);
    }

S
develop  
server 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    public static function checkPackage($token, $module, $version)
    {
        $ret = self::baseRequest('/api/store/module_info', [
            'module' => $module,
            'version' => $version,
        ], $token);
        BizException::throwsIfResponseError($ret);
        $config = $ret['data']['config'];
        $packageSize = $ret['data']['packageSize'];
        $requires = [];
        if (!empty($config['modstartVersion'])) {
            $require = [
                'name' => "<a href='https://modstart.com/download' class='ub-text-white tw-underline' target='_blank'>ModStart</a>:" . htmlspecialchars($config['modstartVersion']),
                'success' => VersionUtil::match(ModStart::$version, $config['modstartVersion']),
                'resolve' => null,
            ];
            if (!$require['success']) {
                $require['resolve'] = '请使用版本 ' . $config['modstartVersion'] . ' 的ModStart核心';
            }
            $requires[] = $require;
        }
        if (!empty($config['require'])) {
            foreach ($config['require'] as $require) {
                list($m, $v) = VersionUtil::parse($require);
                $require = [
                    'name' => "<a href='https://modstart.com/m/$m' class='ub-text-white tw-underline' target='_blank'>$m</a>:" . htmlspecialchars($v),
                    'success' => true,
                    'resolve' => null,
                ];
                if (ModuleManager::isModuleInstalled($m)) {
                    $basic = ModuleManager::getModuleBasic($m);
                    BizException::throwsIfEmpty("获取模块 $m 信息失败", $basic);
                    $require['success'] = VersionUtil::match($basic['version'], $v);
                    if (!$require['success']) {
                        $require['resolve'] = "请使用版本 " . htmlspecialchars($v) . " 的模块 <a href='https://modstart.com/m/$m' class='ub-text-white tw-underline' target='_blank'>$m</a>";
                    }
                } else {
                    $require['success'] = false;
ModStart's avatar
develop  
ModStart 已提交
149
                    $require['resolve'] = "请先安装 $require[name] <a href='https://modstart.com/m/$m' class='ub-text-white tw-underline' target='_blank'>[点击查看]</a>";
S
develop  
server 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162
                }
                $requires[] = $require;
            }
        }
        return Response::generateSuccessData([
            'requires' => $requires,
            'errorCount' => count(array_filter($requires, function ($o) {
                return !$o['success'];
            })),
            'packageSize' => $packageSize,
        ]);
    }

S
develop  
server 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    public static function downloadPackage($token, $module, $version)
    {
        $ret = self::baseRequest('/api/store/module_package', [
            'module' => $module,
            'version' => $version,
        ], $token);
        BizException::throwsIfResponseError($ret);
        $package = $ret['data']['package'];
        $packageMd5 = $ret['data']['packageMd5'];
        $licenseKey = $ret['data']['licenseKey'];
        $data = CurlUtil::getRaw($package);
        BizException::throwsIfEmpty('安装包获取失败', $data);
        $zipTemp = FileUtil::generateLocalTempPath('zip');
        file_put_contents($zipTemp, $data);
        BizException::throwsIf('文件MD5校验失败', md5_file($zipTemp) != $packageMd5);
        return Response::generateSuccessData([
            'package' => $zipTemp,
            'licenseKey' => $licenseKey,
            'packageSize' => filesize($zipTemp),
        ]);
    }

ModStart's avatar
develop  
ModStart 已提交
185 186 187 188 189
    public static function cleanDownloadedPackage($package)
    {
        FileUtil::safeCleanLocalTemp($package);
    }

S
develop  
server 已提交
190 191
    public static function unpackModule($module, $package, $licenseKey)
    {
ModStart's avatar
develop  
ModStart 已提交
192
        $results = [];
S
develop  
server 已提交
193 194 195
        BizException::throwsIf('文件不存在 ' . $package, empty($package) || !file_exists($package));
        $moduleDir = base_path('module/' . $module);
        if (file_exists($moduleDir)) {
ModStart's avatar
develop  
ModStart 已提交
196
            $moduleBackup = '_delete_.' . date('Ymd_His') . '.' . $module;
S
develop  
server 已提交
197
            BizException::throwsIf('模块目录 module/' . $module . ' 不正常,请手动删除', !is_dir($moduleDir));
ModStart's avatar
develop  
ModStart 已提交
198 199 200 201 202 203 204 205
            $moduleBackupDir = base_path("module/$moduleBackup");
            try {
                rename($moduleDir, $moduleBackupDir);
            } catch (\Exception $e) {
                BizException::throws("备份模块 $module$moduleBackup 失败,请确保模块 $module 中没有文件正在被使用");
            }
            BizException::throwsIf('备份模块旧文件失败', !file_exists($moduleBackupDir));
            $results[] = "备份模块 $module$moduleBackup";
S
develop  
server 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218
        }
        BizException::throwsIf('模块目录 module/' . $module . ' 不正常,请手动删除', file_exists($moduleDir));
        $zipper = new Zipper();
        $zipper->make($package);
        if ($zipper->contains($module . '/config.json')) {
            $zipper->folder($module . '');
        }
        $zipper->extractTo($moduleDir);
        $zipper->close();
        BizException::throwsIf('解压失败', !file_exists($moduleDir . '/config.json'));
        file_put_contents($moduleDir . '/license.json', json_encode([
            'licenseKey' => $licenseKey,
        ]));
ModStart's avatar
develop  
ModStart 已提交
219 220
        self::cleanDownloadedPackage($package);
        return Response::generateSuccessData($results);
S
develop  
server 已提交
221 222 223 224 225 226 227
    }

    public static function removeModule($module, $version)
    {
        $moduleDir = base_path('module/' . $module);
        BizException::throwsIf('模块目录不存在 ', !file_exists($moduleDir));
        BizException::throwsIf('模块目录 module/' . $module . ' 不正常,请手动删除', !is_dir($moduleDir));
ModStart's avatar
develop  
ModStart 已提交
228 229 230 231 232 233 234 235
        $moduleBackup = '_delete_.' . date('Ymd_His') . '.' . $module;
        $moduleBackupDir = base_path("module/$moduleBackup");
        try {
            rename($moduleDir, $moduleBackupDir);
        } catch (\Exception $e) {
            BizException::throws("移除模块 $module$moduleBackup 失败,请确保模块 $module 中没有文件正在被使用");
        }
        BizException::throwsIf('模块目录备份失败', !file_exists($moduleBackupDir));
S
develop  
server 已提交
236 237 238 239
        return Response::generateSuccessData([]);
    }

}