仰望星辰工作室

better-staridc-MNBT

better-staridc-MNBT/ docker/head.php 4.8 KB · 148 行 原始文件
Z zfhsh first commit 2 天前
1<?php
2/**
3 * Docker 控制器公共引导
4 * 引入 MNBT 核心环境 + Docker API 封装 + Docker 独立认证
5 */
6if (!defined('IN_CRONLITE')) {
7 define('IN_CRONLITE', true);
8}
9include dirname(__DIR__) . '/MPHX/common.php';
10include_once SYSTEM_ROOT . 'bt_docker.php';
11include_once SYSTEM_ROOT . 'bt_proxy.php';
12include_once SYSTEM_ROOT . 'docker.member.php';
13
14/**
15 * 根据 Docker 用户所属节点构造 bt_docker 实例
16 * @param array $dockerUser MN_docker_user 行
17 * @return array [bt_docker|null, MN_docker_node行|null]
18 */
19function docker_user_node($dockerUser)
20{
21 global $DB;
22 $node = $DB->get_row_prepare("SELECT * FROM MN_docker_node WHERE id=? limit 1", [(int)$dockerUser['ssbt']]);
23 if (!$node || $node['qk'] !== 'true') {
24 return [null, null];
25 }
26 $url = ($node['ptl'] === 'true' ? 'https' : 'http') . '://' . $node['btip'] . ':' . $node['btdk'];
27 return [new bt_docker($url, $node['btmy']), $node];
28}
29
30/**
31 * 根据 Docker 用户所属节点构造 bt_proxy 实例
32 */
33function docker_user_proxy($dockerUser)
34{
35 global $DB;
36 $node = $DB->get_row_prepare("SELECT * FROM MN_docker_node WHERE id=? limit 1", [(int)$dockerUser['ssbt']]);
37 if (!$node || $node['qk'] !== 'true') {
38 return null;
39 }
40 $url = ($node['ptl'] === 'true' ? 'https' : 'http') . '://' . $node['btip'] . ':' . $node['btdk'];
41 return new bt_proxy($url, $node['btmy']);
42}
43
44/**
45 * 获取 Docker 用户套餐
46 */
47function docker_user_plan($dockerUser)
48{
49 global $DB;
50 if (empty($dockerUser['plan_id'])) {
51 return null;
52 }
53 return $DB->get_row_prepare("SELECT * FROM MN_docker_plan WHERE id=? limit 1", [$dockerUser['plan_id']]);
54}
55
56/**
57 * 输出 JSON 并退出
58 */
59function docker_json($code, $msg = '', $extra = [])
60{
61 @header('Content-Type: application/json; charset=UTF-8');
62 $result = array_merge([
63 'success' => ((int)$code === 200 || $code === true),
64 'code' => $code,
65 'msg' => $msg,
66 ], $extra);
67 exit(json_encode($result, JSON_UNESCAPED_UNICODE));
68}
69
70/**
71 * 在用户容器列表中找到属于自己的那一个容器(按 service_name / container_id 匹配)
72 * @param array $dockerUser
73 * @param array $containers bt_docker::container_list() 返回的容器数组
74 * @return array|null
75 */
76function docker_find_my_container($dockerUser, $containers)
77{
78 if (!is_array($containers)) {
79 return null;
80 }
81 // 宝塔 get_list 返回 {container_list: [...], online_cpus, mem_total, gpu}
82 // 兼容 data / 直接数组 两种历史结构
83 $list = $containers['container_list'] ?? $containers['data'] ?? $containers;
84 if (!is_array($list)) {
85 return null;
86 }
87 $sn = (string)($dockerUser['service_name'] ?? '');
88 $cid_stored = (string)($dockerUser['container_id'] ?? '');
89 foreach ($list as $c) {
90 $name = ltrim((string)($c['name'] ?? ($c['Names'][0] ?? '')), '/');
91 // 宝塔字段为 container_id,兼容 id/Id
92 $cid = (string)($c['container_id'] ?? $c['id'] ?? $c['Id'] ?? '');
93 // 1) service_name 精确匹配
94 if ($sn !== '' && $name === $sn) {
95 return $c;
96 }
97 // 2) container_id 精确匹配
98 if ($cid_stored !== '' && $cid !== '' && $cid === $cid_stored) {
99 return $c;
100 }
101 // 3) compose 命名匹配:<service_name>-<app>-N 或 <service_name>_<app>_N
102 // 宝塔 create_app 创建的容器 name 形如 mnbt_xxx-frps-1
103 if ($sn !== '' && $name !== '' && strpos($name, $sn) === 0) {
104 $next = strlen($name) > strlen($sn) ? $name[strlen($sn)] : '';
105 if ($next === '' || $next === '-' || $next === '_') {
106 return $c;
107 }
108 }
109 }
110 return null;
111}
112
113/**
114 * 在已安装应用列表中找到属于自己的那一个应用(按 service_name 匹配)
115 * 宝塔 get_installed_apps 返回的应用信息比 get_list 更丰富(含端口/IP/参数)
116 * @param array $dockerUser
117 * @param array $apps bt_docker::installed_apps() 返回的应用数组
118 * @return array|null|false 找到返回应用数组;节点返回成功但无匹配返回 null;节点请求失败返回 false(调用方不得据此清零用户数据)
119 */
120function docker_find_my_installed_app($dockerUser, $apps)
121{
122 if (!is_array($apps)) {
123 return null;
124 }
125 // 节点请求失败时 bt_docker::request 返回 ['status'=>false,'msg'=>...](无 data),
126 // 必须与"查询成功但无该应用"区分开,否则调用方会把失败响应当成无应用而误清零用户容器数据
127 if (isset($apps['status']) && $apps['status'] === false) {
128 return false;
129 }
130 $list = $apps['data'] ?? $apps;
131 if (!is_array($list)) {
132 return null;
133 }
134 $sn = (string)($dockerUser['service_name'] ?? '');
135 $cid_stored = (string)($dockerUser['container_id'] ?? '');
136 foreach ($list as $a) {
137 // 1) service_name 精确匹配(宝塔 get_installed_apps[].service_name = create_app 时传入的值)
138 if ($sn !== '' && (string)($a['service_name'] ?? '') === $sn) {
139 return $a;
140 }
141 // 2) container_id 精确匹配
142 $cid = (string)($a['container_id'] ?? '');
143 if ($cid_stored !== '' && $cid !== '' && $cid === $cid_stored) {
144 return $a;
145 }
146 }
147 return null;
148}