mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-10-14 09:49:19 +00:00
Compare commits
3 Commits
16eb9cf6db
...
0b6b9624a6
Author | SHA1 | Date | |
---|---|---|---|
0b6b9624a6 | |||
0f8e7fe4d6 | |||
bccdde74ad |
@ -82,7 +82,7 @@ async def test_endpoint():
|
|||||||
@router.get("/scan_network", summary="扫描网络中的交换机")
|
@router.get("/scan_network", summary="扫描网络中的交换机")
|
||||||
async def scan_network(subnet: str = "192.168.1.0/24"):
|
async def scan_network(subnet: str = "192.168.1.0/24"):
|
||||||
try:
|
try:
|
||||||
devices = scanner.scan_subnet(subnet)
|
devices = await scanner.scan_subnet(subnet)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"devices": devices,
|
"devices": devices,
|
||||||
@ -94,7 +94,7 @@ async def scan_network(subnet: str = "192.168.1.0/24"):
|
|||||||
@router.get("/list_devices", summary="列出已发现的交换机")
|
@router.get("/list_devices", summary="列出已发现的交换机")
|
||||||
async def list_devices():
|
async def list_devices():
|
||||||
return {
|
return {
|
||||||
"devices": scanner.load_cached_devices()
|
"devices": await scanner.load_cached_devices()
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommandRequest(BaseModel):
|
class CommandRequest(BaseModel):
|
||||||
@ -125,7 +125,7 @@ async def parse_command(request: CommandRequest):
|
|||||||
@router.post("/apply_config", response_model=dict)
|
@router.post("/apply_config", response_model=dict)
|
||||||
async def apply_config(request: ConfigRequest):
|
async def apply_config(request: ConfigRequest):
|
||||||
"""
|
"""
|
||||||
应用配置到交换机
|
应用配置到交换机(弃用)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
configurator = SwitchConfigurator(
|
configurator = SwitchConfigurator(
|
||||||
|
@ -110,6 +110,9 @@ class SwitchConfigurator:
|
|||||||
|
|
||||||
output = ""
|
output = ""
|
||||||
for cmd in commands:
|
for cmd in commands:
|
||||||
|
if cmd.startswith("!"):
|
||||||
|
logger.debug(f"跳过特殊命令: {cmd}")
|
||||||
|
continue
|
||||||
logger.info(f"发送命令: {cmd}")
|
logger.info(f"发送命令: {cmd}")
|
||||||
writer.write(f"{cmd}\n")
|
writer.write(f"{cmd}\n")
|
||||||
await writer.drain()
|
await writer.drain()
|
||||||
|
@ -42,7 +42,7 @@ class AIService:
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = self.client.chat.completions.create(
|
response = await self.client.chat.completions.create(
|
||||||
model="deepseek-ai/DeepSeek-V3",
|
model="deepseek-ai/DeepSeek-V3",
|
||||||
messages=messages,
|
messages=messages,
|
||||||
temperature=0.3,
|
temperature=0.3,
|
||||||
|
@ -9,7 +9,7 @@ class NetworkScanner:
|
|||||||
self.cache_path = Path(cache_path)
|
self.cache_path = Path(cache_path)
|
||||||
self.nm = nmap.PortScanner()
|
self.nm = nmap.PortScanner()
|
||||||
|
|
||||||
def scan_subnet(self, subnet: str = "192.168.1.0/24", ports: List[int] = [22, 23, 80]) -> List[Dict]:
|
async def scan_subnet(self, subnet: str = "192.168.1.0/24", ports: List[int] = [22, 23, 80]) -> List[Dict]:
|
||||||
"""扫描指定子网的设备,获取设备信息和开放端口"""
|
"""扫描指定子网的设备,获取设备信息和开放端口"""
|
||||||
logger.info(f"Scanning subnet: {subnet}")
|
logger.info(f"Scanning subnet: {subnet}")
|
||||||
|
|
||||||
@ -33,16 +33,16 @@ class NetworkScanner:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error while scanning subnet: {e}")
|
logger.error(f"Error while scanning subnet: {e}")
|
||||||
|
|
||||||
self._save_to_cache(devices)
|
await self._save_to_cache(devices)
|
||||||
return devices
|
return devices
|
||||||
|
|
||||||
def _save_to_cache(self, devices: List[Dict]):
|
async def _save_to_cache(self, devices: List[Dict]):
|
||||||
"""保存扫描结果到本地文件"""
|
"""保存扫描结果到本地文件"""
|
||||||
with open(self.cache_path, "w") as f:
|
with open(self.cache_path, "w") as f:
|
||||||
json.dump(devices, f, indent=2)
|
json.dump(devices, f, indent=2)
|
||||||
logger.info(f"Saved {len(devices)} devices to cache")
|
logger.info(f"Saved {len(devices)} devices to cache")
|
||||||
|
|
||||||
def load_cached_devices(self) -> List[Dict]:
|
async def load_cached_devices(self) -> List[Dict]:
|
||||||
"""从缓存加载设备列表"""
|
"""从缓存加载设备列表"""
|
||||||
if not self.cache_path.exists():
|
if not self.cache_path.exists():
|
||||||
return []
|
return []
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
"@nestjs/swagger": "^11.2.0",
|
"@nestjs/swagger": "^11.2.0",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
|
"ip": "^2.0.1",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"ssh2": "^1.16.0"
|
"ssh2": "^1.16.0"
|
||||||
@ -34,6 +35,7 @@
|
|||||||
"@swc/cli": "^0.6.0",
|
"@swc/cli": "^0.6.0",
|
||||||
"@swc/core": "^1.10.7",
|
"@swc/core": "^1.10.7",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
|
"@types/ip": "^1.1.3",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/node": "^22.16.4",
|
"@types/node": "^22.16.4",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
|
8288
src/nest-backend/pnpm-lock.yaml
generated
8288
src/nest-backend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,13 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { RootModule } from './root/root.module';
|
import { RootModule } from './root/root.module';
|
||||||
|
import { HttpMiddleware } from './common/middleware/http.middleware';
|
||||||
|
import { NetworkModule } from './modules/network/network.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [RootModule],
|
imports: [RootModule, NetworkModule],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule implements NestModule {
|
||||||
|
configure(consumer: MiddlewareConsumer): any {
|
||||||
|
consumer.apply(HttpMiddleware).forRoutes('api');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import {
|
|
||||||
ArgumentsHost,
|
|
||||||
Catch,
|
|
||||||
ExceptionFilter,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
|
|
||||||
@Catch()
|
|
||||||
export class AllExceptionsFilter implements ExceptionFilter {
|
|
||||||
catch(exception: unknown, host: ArgumentsHost) {
|
|
||||||
const ctx = host.switchToHttp();
|
|
||||||
const response = ctx.getResponse();
|
|
||||||
const status =
|
|
||||||
exception instanceof HttpException
|
|
||||||
? exception.getStatus()
|
|
||||||
: HttpStatus.INTERNAL_SERVER_ERROR;
|
|
||||||
|
|
||||||
const message =
|
|
||||||
exception instanceof HttpException ? exception.message : '服务器内部错误';
|
|
||||||
|
|
||||||
response.status(status).json({
|
|
||||||
success: false,
|
|
||||||
data: null,
|
|
||||||
message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,6 @@ export class ResponseInterceptor<T>
|
|||||||
map((data) => ({
|
map((data) => ({
|
||||||
success: true,
|
success: true,
|
||||||
data,
|
data,
|
||||||
message: '操作成功',
|
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
25
src/nest-backend/src/common/middleware/http.middleware.ts
Normal file
25
src/nest-backend/src/common/middleware/http.middleware.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
|
||||||
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HttpMiddleware implements NestMiddleware {
|
||||||
|
private readonly logger = new Logger('HTTP');
|
||||||
|
|
||||||
|
use(req: Request, res: Response, next: NextFunction): void {
|
||||||
|
const { method, originalUrl } = req;
|
||||||
|
this.logger.log(`HTTP request for ${method} ${originalUrl}`);
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
res.on('finish', () => {
|
||||||
|
const statusCode = res.statusCode;
|
||||||
|
const contentLength = res.get('content-length') || 0;
|
||||||
|
const duration = Date.now() - startTime;
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`${method} ${originalUrl} ${statusCode} ${contentLength}B - ${duration}ms`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
export interface ApiResponse<T = any> {
|
export interface ApiResponse<T = any> {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
data: T;
|
data: T;
|
||||||
message: string;
|
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,11 @@ import { AppModule } from './app.module';
|
|||||||
import { Logger } from '@nestjs/common';
|
import { Logger } from '@nestjs/common';
|
||||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
||||||
import { AllExceptionsFilter } from './common/filters/all-exception.filter';
|
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
app.setGlobalPrefix('api');
|
app.setGlobalPrefix('api');
|
||||||
app.useGlobalInterceptors(new ResponseInterceptor());
|
app.useGlobalInterceptors(new ResponseInterceptor());
|
||||||
app.useGlobalFilters(new AllExceptionsFilter());
|
|
||||||
const config = new DocumentBuilder()
|
const config = new DocumentBuilder()
|
||||||
.setTitle('交换机API平台')
|
.setTitle('交换机API平台')
|
||||||
.setDescription('自动化交换机配置和流量监控接口')
|
.setDescription('自动化交换机配置和流量监控接口')
|
||||||
|
18
src/nest-backend/src/modules/network/network.controller.ts
Normal file
18
src/nest-backend/src/modules/network/network.controller.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Controller, Get, Inject } from '@nestjs/common';
|
||||||
|
import { NetworkService } from './network.service';
|
||||||
|
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@ApiTags('Network')
|
||||||
|
@Controller('network')
|
||||||
|
export class NetworkController {
|
||||||
|
constructor(
|
||||||
|
@Inject(NetworkService)
|
||||||
|
private readonly networkService: NetworkService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Get('adapters')
|
||||||
|
@ApiOperation({ summary: '获取网络适配器网段' })
|
||||||
|
async getNetworkAdapters() {
|
||||||
|
return this.networkService.getNetworkAdapters();
|
||||||
|
}
|
||||||
|
}
|
10
src/nest-backend/src/modules/network/network.module.ts
Normal file
10
src/nest-backend/src/modules/network/network.module.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { NetworkService } from './network.service';
|
||||||
|
import { NetworkController } from './network.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [NetworkController],
|
||||||
|
providers: [NetworkService],
|
||||||
|
exports: [NetworkService],
|
||||||
|
})
|
||||||
|
export class NetworkModule {}
|
44
src/nest-backend/src/modules/network/network.service.ts
Normal file
44
src/nest-backend/src/modules/network/network.service.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import os from 'os';
|
||||||
|
import ip from 'ip';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class NetworkService {
|
||||||
|
private readonly logger = new Logger(NetworkService.name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网络适配器信息及网段
|
||||||
|
*/
|
||||||
|
async getNetworkAdapters(): Promise<any> {
|
||||||
|
try {
|
||||||
|
this.logger.log('Getting network adapters');
|
||||||
|
const interfaces = os.networkInterfaces();
|
||||||
|
const networks: any[] = [];
|
||||||
|
|
||||||
|
for (const [adapter, addrs] of Object.entries(interfaces)) {
|
||||||
|
if (!addrs) continue;
|
||||||
|
|
||||||
|
for (const addr of addrs) {
|
||||||
|
if (addr.family === 'IPv4' && !addr.internal) {
|
||||||
|
const ipAddress = addr.address;
|
||||||
|
const subnetMask = addr.netmask;
|
||||||
|
const cidr = ip.subnet(ipAddress, subnetMask);
|
||||||
|
const networkCidr = `${cidr.networkAddress}/${cidr.subnetMaskLength}`;
|
||||||
|
|
||||||
|
networks.push({
|
||||||
|
adapter,
|
||||||
|
network: networkCidr,
|
||||||
|
ip: ipAddress,
|
||||||
|
subnet_mask: subnetMask,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { networks };
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('获取网络适配器信息失败', error);
|
||||||
|
return { error: `获取网络适配器信息失败: ${error.message}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { Controller, Get } from '@nestjs/common';
|
|||||||
@Controller()
|
@Controller()
|
||||||
export class RootController {
|
export class RootController {
|
||||||
@Get()
|
@Get()
|
||||||
getWelcome() {
|
async getWelcome() {
|
||||||
return {
|
return {
|
||||||
message: '欢迎使用交换机管理平台 API',
|
message: '欢迎使用交换机管理平台 API',
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { RootController } from './root.controller';
|
import { RootController } from './root.controller';
|
||||||
|
import { HttpMiddleware } from '../common/middleware/http.middleware';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [RootController],
|
controllers: [RootController],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user