403 lines
12 KiB
PHP
403 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\PrintPlugin;
|
|
use App\Models\PrintPluginInstallation;
|
|
use App\Models\PrintPluginLog;
|
|
use App\Models\PrintJob;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class PrintPluginService
|
|
{
|
|
/**
|
|
* 获取所有插件列表
|
|
*/
|
|
public function getPlugins(?string $platform = null): array
|
|
{
|
|
$query = PrintPlugin::where('status', '!=', 'inactive');
|
|
|
|
if ($platform) {
|
|
$query->where('platform', $platform);
|
|
}
|
|
|
|
$plugins = $query->get()->map(function ($plugin) {
|
|
return $this->formatPluginInfo($plugin);
|
|
});
|
|
|
|
return $plugins->toArray();
|
|
}
|
|
|
|
/**
|
|
* 获取插件详情
|
|
*/
|
|
public function getPlugin(string $code): ?array
|
|
{
|
|
$plugin = PrintPlugin::where('code', $code)->first();
|
|
|
|
if (!$plugin) {
|
|
return null;
|
|
}
|
|
|
|
return $this->formatPluginInfo($plugin, true);
|
|
}
|
|
|
|
/**
|
|
* 获取插件最新版本信息
|
|
*/
|
|
public function getLatestVersion(string $code): ?array
|
|
{
|
|
$plugin = PrintPlugin::where('code', $code)->first();
|
|
|
|
if (!$plugin) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'code' => $plugin->code,
|
|
'name' => $plugin->name,
|
|
'version' => $plugin->version,
|
|
'download_url' => $plugin->download_url,
|
|
'md5' => $plugin->md5,
|
|
'file_size' => $plugin->file_size,
|
|
'changelog' => $plugin->changelog,
|
|
'min_erp_version' => $plugin->min_erp_version,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 下载插件安装包
|
|
*/
|
|
public function downloadPlugin(string $code): ?string
|
|
{
|
|
$plugin = PrintPlugin::where('code', $code)->first();
|
|
|
|
if (!$plugin) {
|
|
return null;
|
|
}
|
|
|
|
// 本地存储路径
|
|
$storagePath = storage_path("app/plugins/{$code}/");
|
|
$fileName = "{$plugin->version}.{$plugin->install_type}";
|
|
$fullPath = $storagePath . $fileName;
|
|
|
|
// 如果已存在直接返回
|
|
if (file_exists($fullPath)) {
|
|
return $fullPath;
|
|
}
|
|
|
|
// 创建目录
|
|
if (!is_dir($storagePath)) {
|
|
mkdir($storagePath, 0755, true);
|
|
}
|
|
|
|
try {
|
|
$response = Http::timeout(60)->sink($fullPath)->get($plugin->download_url);
|
|
|
|
if ($response->successful()) {
|
|
// 验证MD5
|
|
if ($plugin->md5 && md5_file($fullPath) !== $plugin->md5) {
|
|
unlink($fullPath);
|
|
Log::error("Plugin download MD5 mismatch: {$code}");
|
|
return null;
|
|
}
|
|
return $fullPath;
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error("Plugin download failed: {$e->getMessage()}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 检查用户设备上的插件版本
|
|
*/
|
|
public function checkUserPluginVersion(int $userId, string $pluginCode, string $deviceId): ?array
|
|
{
|
|
$installation = PrintPluginInstallation::where('user_id', $userId)
|
|
->where('device_id', $deviceId)
|
|
->whereHas('plugin', function ($q) use ($pluginCode) {
|
|
$q->where('code', $pluginCode);
|
|
})
|
|
->with('plugin')
|
|
->first();
|
|
|
|
if (!$installation) {
|
|
return null;
|
|
}
|
|
|
|
$plugin = $installation->plugin;
|
|
$hasUpdate = $plugin->hasNewVersion($installation->installed_version);
|
|
|
|
return [
|
|
'installed' => true,
|
|
'version' => $installation->installed_version,
|
|
'has_update' => $hasUpdate,
|
|
'latest_version' => $hasUpdate ? $plugin->version : null,
|
|
'device_id' => $installation->device_id,
|
|
'device_name' => $installation->device_name,
|
|
'is_online' => $installation->isOnline(),
|
|
'last_heartbeat' => $installation->last_heartbeat?->toIso8601String(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取用户已安装的插件
|
|
*/
|
|
public function getUserInstallations(int $userId): array
|
|
{
|
|
$installations = PrintPluginInstallation::where('user_id', $userId)
|
|
->with('plugin')
|
|
->get();
|
|
|
|
return $installations->map(function ($installation) {
|
|
$plugin = $installation->plugin;
|
|
return [
|
|
'id' => $installation->id,
|
|
'plugin_code' => $plugin->code,
|
|
'plugin_name' => $plugin->name,
|
|
'platform' => $plugin->platform,
|
|
'installed_version' => $installation->installed_version,
|
|
'latest_version' => $plugin->version,
|
|
'has_update' => $plugin->hasNewVersion($installation->installed_version),
|
|
'device_id' => $installation->device_id,
|
|
'device_name' => $installation->device_name,
|
|
'install_status' => $installation->install_status,
|
|
'is_online' => $installation->isOnline(),
|
|
'last_heartbeat' => $installation->last_heartbeat?->toIso8601String(),
|
|
'installed_at' => $installation->installed_at?->toIso8601String(),
|
|
];
|
|
})->toArray();
|
|
}
|
|
|
|
/**
|
|
* 注册插件安装
|
|
*/
|
|
public function registerInstallation(
|
|
int $userId,
|
|
string $pluginCode,
|
|
string $version,
|
|
string $deviceId,
|
|
?string $deviceName = null,
|
|
?string $osVersion = null
|
|
): array {
|
|
$plugin = PrintPlugin::where('code', $pluginCode)->first();
|
|
|
|
if (!$plugin) {
|
|
return ['success' => false, 'message' => '插件不存在'];
|
|
}
|
|
|
|
$installation = PrintPluginInstallation::updateOrCreate(
|
|
[
|
|
'user_id' => $userId,
|
|
'plugin_id' => $plugin->id,
|
|
'device_id' => $deviceId,
|
|
],
|
|
[
|
|
'installed_version' => $version,
|
|
'device_name' => $deviceName,
|
|
'os_version' => $osVersion,
|
|
'install_status' => 'active',
|
|
'last_heartbeat' => now(),
|
|
'installed_at' => now(),
|
|
]
|
|
);
|
|
|
|
// 记录日志
|
|
PrintPluginLog::record(
|
|
$userId,
|
|
PrintPluginLog::TYPE_INSTALL,
|
|
"安装插件 {$plugin->name} v{$version}",
|
|
$plugin->id,
|
|
null,
|
|
['version' => $version, 'device_id' => $deviceId, 'device_name' => $deviceName]
|
|
);
|
|
|
|
return [
|
|
'success' => true,
|
|
'installation_id' => $installation->id,
|
|
'has_update' => $plugin->hasNewVersion($version),
|
|
'latest_version' => $plugin->version,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 记录心跳
|
|
*/
|
|
public function recordHeartbeat(int $userId, string $deviceId): bool
|
|
{
|
|
$installation = PrintPluginInstallation::where('user_id', $userId)
|
|
->where('device_id', $deviceId)
|
|
->first();
|
|
|
|
if ($installation) {
|
|
$installation->recordHeartbeat();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 卸载插件
|
|
*/
|
|
public function uninstall(int $userId, string $pluginCode, string $deviceId): bool
|
|
{
|
|
$installation = PrintPluginInstallation::whereHas('plugin', function ($q) use ($pluginCode) {
|
|
$q->where('code', $pluginCode);
|
|
})
|
|
->where('user_id', $userId)
|
|
->where('device_id', $deviceId)
|
|
->first();
|
|
|
|
if ($installation) {
|
|
$installation->update(['install_status' => 'uninstalled']);
|
|
|
|
PrintPluginLog::record(
|
|
$userId,
|
|
PrintPluginLog::TYPE_UNINSTALL,
|
|
"卸载插件",
|
|
$installation->plugin_id,
|
|
null,
|
|
['device_id' => $deviceId]
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 获取设备状态
|
|
*/
|
|
public function getDeviceStatus(int $userId, string $deviceId): array
|
|
{
|
|
$installations = PrintPluginInstallation::where('user_id', $userId)
|
|
->where('device_id', $deviceId)
|
|
->with('plugin')
|
|
->get();
|
|
|
|
if ($installations->isEmpty()) {
|
|
return ['online' => false, 'plugins' => []];
|
|
}
|
|
|
|
return [
|
|
'online' => $installations->contains(fn($i) => $i->isOnline()),
|
|
'plugins' => $installations->map(fn($i) => [
|
|
'code' => $i->plugin->code,
|
|
'name' => $i->plugin->name,
|
|
'is_online' => $i->isOnline(),
|
|
'last_heartbeat' => $i->last_heartbeat?->toIso8601String(),
|
|
])->toArray(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 格式化插件信息
|
|
*/
|
|
protected function formatPluginInfo(PrintPlugin $plugin, bool $withVersions = false): array
|
|
{
|
|
$data = [
|
|
'id' => $plugin->id,
|
|
'code' => $plugin->code,
|
|
'name' => $plugin->name,
|
|
'platform' => $plugin->platform,
|
|
'platform_name' => PrintPlugin::getPlatformName($plugin->platform),
|
|
'version' => $plugin->version,
|
|
'download_url' => $plugin->download_url,
|
|
'md5' => $plugin->md5,
|
|
'file_size' => $plugin->file_size,
|
|
'install_type' => $plugin->install_type,
|
|
'min_erp_version' => $plugin->min_erp_version,
|
|
'status' => $plugin->status,
|
|
'published_at' => $plugin->published_at?->toIso8601String(),
|
|
];
|
|
|
|
if ($withVersions) {
|
|
$data['changelog'] = $plugin->changelog;
|
|
$data['config'] = $plugin->config;
|
|
$data['versions'] = $plugin->versions()->orderByDesc('published_at')->take(10)->get()->map(fn($v) => [
|
|
'version' => $v->version,
|
|
'changelog' => $v->changelog,
|
|
'published_at' => $v->published_at?->toIso8601String(),
|
|
])->toArray();
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 检测插件更新(定时任务调用)
|
|
*/
|
|
public function checkUpdates(string $pluginCode): ?array
|
|
{
|
|
$plugin = PrintPlugin::where('code', $pluginCode)->first();
|
|
|
|
if (!$plugin || empty($plugin->config['update_check_url'])) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$response = Http::timeout(30)->get($plugin->config['update_check_url']);
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
$latestVersion = $data['version'] ?? null;
|
|
|
|
if ($latestVersion && version_compare($latestVersion, $plugin->version) > 0) {
|
|
// 有新版本
|
|
$plugin->update([
|
|
'version' => $latestVersion,
|
|
'download_url' => $data['download_url'] ?? $plugin->download_url,
|
|
'md5' => $data['md5'] ?? $plugin->md5,
|
|
'changelog' => $data['changelog'] ?? $plugin->changelog,
|
|
'file_size' => $data['file_size'] ?? $plugin->file_size,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
return [
|
|
'code' => $plugin->code,
|
|
'old_version' => $plugin->getOriginal('version'),
|
|
'new_version' => $latestVersion,
|
|
'changelog' => $data['changelog'] ?? '',
|
|
];
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error("Check plugin update failed: {$e->getMessage()}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 获取需要通知更新的用户
|
|
*/
|
|
public function getUsersNeedingUpdate(string $pluginCode): array
|
|
{
|
|
$plugin = PrintPlugin::where('code', $pluginCode)->first();
|
|
|
|
if (!$plugin) {
|
|
return [];
|
|
}
|
|
|
|
return PrintPluginInstallation::where('plugin_id', $plugin->id)
|
|
->where('install_status', 'active')
|
|
->whereColumn('installed_version', '!=', 'installed_version') // 需要简化
|
|
->get()
|
|
->filter(fn($i) => version_compare($i->installed_version, $plugin->version) < 0)
|
|
->map(fn($i) => [
|
|
'user_id' => $i->user_id,
|
|
'device_id' => $i->device_id,
|
|
'current_version' => $i->installed_version,
|
|
'latest_version' => $plugin->version,
|
|
])
|
|
->toArray();
|
|
}
|
|
}
|