320 lines
7.4 KiB
TypeScript
320 lines
7.4 KiB
TypeScript
'use server'
|
|
|
|
import { Page, Res } from '@/lib/api'
|
|
import drizzle, { and, change, cityhash, count, desc, edge, eq, gateway, is, sql, token } from '@/lib/drizzle'
|
|
import { cache } from 'react'
|
|
|
|
export type AllocationStatus = {
|
|
city: string
|
|
count: number
|
|
assigned: number
|
|
}
|
|
|
|
// 城市分配状态
|
|
export async function getAllocationStatus(hours: number = 24) {
|
|
try {
|
|
const c1 = drizzle
|
|
.select({
|
|
cityId: edge.cityId,
|
|
count: count().as('count'),
|
|
})
|
|
.from(edge)
|
|
.where(eq(edge.active, 1))
|
|
.groupBy(edge.cityId)
|
|
.as('c1')
|
|
|
|
const c2 = drizzle
|
|
.select({
|
|
cityId: change.city,
|
|
assigned: count().as('assigned'),
|
|
})
|
|
.from(change)
|
|
.where(sql`time > NOW() - INTERVAL ${hours} HOUR`)
|
|
.groupBy(change.city)
|
|
.as('c2')
|
|
|
|
const result = await drizzle
|
|
.select({
|
|
city: cityhash.city,
|
|
count: sql<number>`c1.count`,
|
|
assigned: sql<number>`ifnull(c2.assigned, 0)`,
|
|
})
|
|
.from(cityhash)
|
|
.leftJoin(c1, eq(c1.cityId, cityhash.id))
|
|
.leftJoin(c2, eq(c2.cityId, cityhash.id))
|
|
.where(sql`cityhash.macaddr is not null`)
|
|
|
|
return {
|
|
success: true,
|
|
data: result,
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Allocation status query error:', error)
|
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
return {
|
|
success: false,
|
|
data: [],
|
|
error: '查询分配状态失败: ' + errorMessage,
|
|
}
|
|
}
|
|
}
|
|
|
|
export type GatewayInfo = {
|
|
macaddr: string
|
|
inner_ip: string
|
|
setid: number
|
|
enable: number
|
|
}
|
|
|
|
// 获取网关基本信息
|
|
export async function getGatewayInfo() {
|
|
try {
|
|
const result = await drizzle
|
|
.select({
|
|
macaddr: token.macaddr,
|
|
inner_ip: token.innerIp,
|
|
setid: token.setid,
|
|
enable: token.enable,
|
|
})
|
|
.from(token)
|
|
.orderBy(sql`cast(regexp_replace(token.inner_ip, '192.168.50.', '') as unsigned)`)
|
|
|
|
return {
|
|
success: true,
|
|
data: result,
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Gateway info query error:', error)
|
|
return {
|
|
success: false,
|
|
data: [],
|
|
error: '查询网关信息失败',
|
|
}
|
|
}
|
|
}
|
|
|
|
export type GatewayConfig = {
|
|
city: string | null
|
|
edge: string
|
|
user: string
|
|
public: string | null
|
|
inner_ip: string
|
|
ischange: number
|
|
isonline: number
|
|
}
|
|
|
|
// 网关配置
|
|
export const getGatewayConfig = cache(async (page?: number, filters?: {
|
|
mac?: string
|
|
public?: string
|
|
city?: string
|
|
user?: string
|
|
inner_ip?: string
|
|
}): Promise<Res<Page<GatewayConfig>>> => {
|
|
try {
|
|
if (!page && !filters?.mac) {
|
|
throw new Error('页码和MAC地址不能同时为空')
|
|
}
|
|
|
|
page = filters?.mac ? 1 : Math.max(1, page || 1)
|
|
|
|
const condition = filters ? and(
|
|
filters.mac ? eq(gateway.macaddr, filters.mac) : undefined,
|
|
filters.public ? eq(edge.public, filters.public) : undefined,
|
|
filters.city ? eq(cityhash.city, filters.city) : undefined,
|
|
filters.user ? eq(gateway.user, filters.user) : undefined,
|
|
filters.inner_ip ? eq(gateway.network, filters.inner_ip) : undefined,
|
|
) : undefined
|
|
|
|
const [total, result] = await Promise.all([
|
|
drizzle
|
|
.select({
|
|
value: count(),
|
|
})
|
|
.from(gateway)
|
|
.leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash))
|
|
.leftJoin(edge, eq(edge.macaddr, gateway.edge))
|
|
.where(condition),
|
|
drizzle
|
|
.select({
|
|
city: cityhash.city,
|
|
edge: gateway.edge,
|
|
user: gateway.user,
|
|
public: edge.public,
|
|
inner_ip: gateway.network,
|
|
ischange: gateway.ischange,
|
|
isonline: gateway.isonline,
|
|
})
|
|
.from(gateway)
|
|
.leftJoin(cityhash, eq(cityhash.hash, gateway.cityhash))
|
|
.leftJoin(edge, eq(edge.macaddr, gateway.edge))
|
|
.where(condition)
|
|
.orderBy(sql`inet_aton(gateway.inner_ip)`)
|
|
.offset((page - 1) * 250)
|
|
.limit(250),
|
|
])
|
|
return {
|
|
success: true,
|
|
data: {
|
|
total: total[0].value,
|
|
page,
|
|
size: 250,
|
|
items: result,
|
|
},
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Gateway config query error:', error)
|
|
return {
|
|
success: false,
|
|
error: '查询网关配置失败',
|
|
}
|
|
}
|
|
})
|
|
|
|
export type CityNode = {
|
|
city: string
|
|
count: number
|
|
hash: string
|
|
label: string | null
|
|
offset: number
|
|
}
|
|
|
|
// 城市节点数量分布
|
|
export async function getCityNodeCount() {
|
|
try {
|
|
const e = drizzle
|
|
.select({
|
|
cityId: edge.cityId,
|
|
count: count().as('count'),
|
|
})
|
|
.from(edge)
|
|
.where(eq(edge.active, 1))
|
|
.groupBy(edge.cityId)
|
|
.as('e')
|
|
|
|
const result = await drizzle
|
|
.select({
|
|
city: cityhash.city,
|
|
hash: cityhash.hash,
|
|
label: cityhash.label,
|
|
count: sql<number>`ifnull(e.count, 0)`,
|
|
offset: cityhash.offset,
|
|
})
|
|
.from(cityhash)
|
|
.leftJoin(e, eq(e.cityId, cityhash.id))
|
|
.groupBy(cityhash.hash)
|
|
.orderBy(desc(sql`e.count`))
|
|
|
|
return {
|
|
success: true,
|
|
data: result,
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('City node count query error:', error)
|
|
return {
|
|
success: false,
|
|
data: [],
|
|
error: '查询城市节点失败',
|
|
}
|
|
}
|
|
}
|
|
|
|
export type Edge = {
|
|
id: number
|
|
macaddr: string
|
|
city: string | null
|
|
public: string
|
|
isp: string
|
|
single: number | boolean
|
|
sole: number | boolean
|
|
arch: number
|
|
online: number
|
|
}
|
|
|
|
// 获取节点信息
|
|
export async function getEdgeNodes(page: number, size: number, filters?: {
|
|
macaddr?: string
|
|
public?: string
|
|
city?: string
|
|
isp?: string
|
|
}): Promise<Res<Page<Edge>>> {
|
|
try {
|
|
page = Math.max(1, page)
|
|
size = Math.min(100, Math.max(10, size))
|
|
|
|
const condition = and(
|
|
eq(edge.active, 1),
|
|
filters?.macaddr ? eq(edge.macaddr, filters.macaddr) : undefined,
|
|
filters?.public ? eq(edge.public, filters.public) : undefined,
|
|
filters?.city ? eq(cityhash.city, filters.city) : undefined,
|
|
filters?.isp ? eq(edge.isp, filters.isp) : undefined,
|
|
)
|
|
|
|
console.log(drizzle
|
|
.select({
|
|
id: edge.id,
|
|
macaddr: edge.macaddr,
|
|
city: cityhash.city,
|
|
public: edge.public,
|
|
isp: edge.isp,
|
|
single: edge.single,
|
|
sole: edge.sole,
|
|
arch: edge.arch,
|
|
online: edge.online,
|
|
})
|
|
.from(edge)
|
|
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
|
|
.where(condition)
|
|
.orderBy(edge.id)
|
|
.offset(page * size - size)
|
|
.limit(size).toSQL().sql)
|
|
|
|
const [total, items] = await Promise.all([
|
|
drizzle
|
|
.select({ value: count() })
|
|
.from(edge)
|
|
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
|
|
.where(condition),
|
|
drizzle
|
|
.select({
|
|
id: edge.id,
|
|
macaddr: edge.macaddr,
|
|
city: cityhash.city,
|
|
public: edge.public,
|
|
isp: edge.isp,
|
|
single: edge.single,
|
|
sole: edge.sole,
|
|
arch: edge.arch,
|
|
online: edge.online,
|
|
})
|
|
.from(edge)
|
|
.leftJoin(cityhash, eq(cityhash.id, edge.cityId))
|
|
.where(condition)
|
|
.orderBy(edge.id)
|
|
.offset(page * size - size)
|
|
.limit(size),
|
|
])
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
total: total[0].value,
|
|
page,
|
|
size,
|
|
items,
|
|
},
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Edge nodes query error:', error)
|
|
return {
|
|
success: false,
|
|
error: '查询边缘节点失败',
|
|
}
|
|
}
|
|
}
|