Files
console-dev/app/lib/cloud-instance-management.js
T

171 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 云实例管理表单的协议校验:防御报价、订单、NAT、VPC 和磁盘规格。 */
var e = (e) => e === `mf_cloud` || e === `remf_cloud`;
// 空对象表示没有防御选项;非空配置必须给出合法的 defence 列表及当前防御值。
function t(e) {
let t = () => {
throw Error(`防御配置无效,请重试`);
};
if (!e || typeof e != `object` || Array.isArray(e)) return t();
let n = e;
if (!Object.keys(n).length)
return {
options: [],
current: ``,
};
let r = n.defence;
if (
!r ||
typeof r != `object` ||
(!Array.isArray(r) && Object.keys(r).some((e) => !/^(0|[1-9]\d*)$/.test(e)))
)
return t();
let i = Object.values(r).map((e) => {
if (!e || typeof e != `object`) return t();
let { value: n, desc: r } = e;
return ![`string`, `number`].includes(typeof n) ||
String(n).trim() === `` ||
!Number.isFinite(Number(n)) ||
Number(n) < 0 ||
![`string`, `number`].includes(typeof r) ||
String(r).trim() === ``
? t()
: {
value: String(n),
desc: String(r),
};
}),
a = n.current_defence == null ? `` : String(n.current_defence);
return a !== `` && (!Number.isFinite(Number(a)) || Number(a) < 0 || !a.trim())
? t()
: {
options: i,
current: a,
};
}
// 允许价格为 0,但不能把缺失值或空串转换成免费报价。
function n(e) {
if (
e == null ||
String(e).trim() === `` ||
!Number.isFinite(Number(e)) ||
Number(e) < 0
)
throw Error(`未获得有效报价,请重试`);
return String(e);
}
// 未取得明确订单号时阻止进入支付;提示先核对订单,避免用户重复下单。
function r(e) {
if (
(typeof e != `string` && typeof e != `number`) ||
!/^[1-9]\d*$/.test(String(e))
)
throw Error(`订单编号未返回,请先在订单管理中检查,避免重复下单`);
return e;
}
/** web 转发只提交域名/内部端口;其他转发使用协议码,null 外部端口表示由后端分配。 */
function i(e, t) {
if (!Number.isInteger(t.int_port) || t.int_port < 1 || t.int_port > 65535)
throw Error(`内部端口应为 1–65535 的整数`);
if (e === `web`) {
let e = t.domain.trim().toLowerCase();
if (
!/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(
e,
)
)
throw Error(`请输入有效域名,不含协议和路径`);
return {
domain: e,
int_port: t.int_port,
};
}
if (!t.name.trim()) throw Error(`请输入转发名称`);
if (![1, 2, 3].includes(t.protocol)) throw Error(`请选择有效协议`);
if (
t.ext_port !== null &&
(!Number.isInteger(t.ext_port) ||
t.ext_port < 0 ||
t.ext_port > 65535 ||
[22, 80, 443].includes(t.ext_port))
)
throw Error(`外部端口应为 0–65535,且不能使用 22、80、443`);
return {
name: t.name.trim(),
int_port: t.int_port,
protocol: t.protocol,
...(t.ext_port === null
? {}
: {
ext_port: t.ext_port,
}),
};
}
/** VPC 名称必填;网段可留空由后端处理,填写时须满足 IPv4 CIDR 及允许掩码。 */
function a(e, t, n = []) {
if (!e.trim()) throw Error(`请输入 VPC 名称`);
if (!t.trim())
return {
name: e.trim(),
};
let r = t.trim().match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/);
if (!r) throw Error(`请输入有效 IPv4 CIDR 网段`);
let i = r.slice(1, 5).map(Number),
a = Number(r[5]);
if (
i.some((e) => e < 0 || e > 255) ||
a < 1 ||
a > 32 ||
(n.length && !n.includes(a))
)
throw Error(`网段地址或掩码不在允许范围内`);
return {
name: e.trim(),
ips: t.trim(),
};
}
// 将磁盘档位转换为可选范围,并向内对齐步长;无合法容量区间的档位不展示。
function o(e, t = {}) {
return e.flatMap((e, n) => {
let r = e.type === `step` || e.type === `total`,
i =
Number(t.disk_range_limit_switch) === 1 &&
Number(t.disk_range_limit) > 0
? Number(t.disk_range_limit)
: 1,
a = r
? Math.ceil(Number(e.min_value ?? e.value) / i) * i
: Number(e.value),
o = r
? Math.floor(Number(e.max_value ?? e.value) / i) * i
: Number(e.value),
s = String(e.other_config?.disk_type ?? ``);
return !Number.isInteger(a) ||
!Number.isInteger(o) ||
a < 1 ||
o < a ||
!Number.isFinite(i) ||
i <= 0
? []
: [
{
id: n,
type: s,
min: a,
max: o,
step: i,
label: `${s || `默认类型`} · ${a === o ? a : `${a}–${o}`} GB`,
},
];
});
}
// 同时检查整数、上下界和步长;浮点容差仅用于除法误差,不放宽容量边界。
function s(e, t) {
return (
Number.isInteger(e) &&
e >= t.min &&
e <= t.max &&
Math.abs((e - t.min) / t.step - Math.round((e - t.min) / t.step)) < 1e-7
);
}
export { i as a, a as c, e as i, t as n, s as o, o as r, r as s, n as t };