model
This commit is contained in:
		@@ -1,26 +0,0 @@
 | 
				
			|||||||
from fastapi import WebSocket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# 使用字典来存储websocket连接
 | 
					 | 
				
			||||||
class ConnectionManager:
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        self.active_connections: map = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 加入一个新的websocket连接
 | 
					 | 
				
			||||||
    async def connect(self, websocket: WebSocket, client_id: int):
 | 
					 | 
				
			||||||
        await websocket.accept()
 | 
					 | 
				
			||||||
        self.active_connections[client_id] = websocket
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 删除一个websocket连接(要先检查client_id是否存在)
 | 
					 | 
				
			||||||
    def disconnect(self, client_id: int):
 | 
					 | 
				
			||||||
        if client_id in self.active_connections:
 | 
					 | 
				
			||||||
            del self.active_connections[client_id]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 向指定的websocket连接发送消息(要先检查client_id是否存在)
 | 
					 | 
				
			||||||
    async def send_personal_message(self, message: str, client_id: int):
 | 
					 | 
				
			||||||
        if client_id in self.active_connections:
 | 
					 | 
				
			||||||
            await self.active_connections[client_id].send_text(message)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 向所有的websocket连接发送消息
 | 
					 | 
				
			||||||
    async def broadcast(self, message: str):
 | 
					 | 
				
			||||||
        for client_id, ws in self.active_connections.items():
 | 
					 | 
				
			||||||
            await ws.send_text(message)
 | 
					 | 
				
			||||||
							
								
								
									
										86
									
								
								ObjectManager.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								ObjectManager.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					from fastapi import WebSocket
 | 
				
			||||||
 | 
					from pydantic import BaseModel
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 使用字典来存储websocket连接
 | 
				
			||||||
 | 
					class ConnectionManager:
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.active_connections: map = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 加入一个新的websocket连接
 | 
				
			||||||
 | 
					    async def connect(self, websocket: WebSocket, client_id: int):
 | 
				
			||||||
 | 
					        await websocket.accept()
 | 
				
			||||||
 | 
					        self.active_connections[client_id] = websocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 删除一个websocket连接(要先检查client_id是否存在)
 | 
				
			||||||
 | 
					    def disconnect(self, client_id: int):
 | 
				
			||||||
 | 
					        if client_id in self.active_connections:
 | 
				
			||||||
 | 
					            del self.active_connections[client_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 向指定的websocket连接发送消息(要先检查client_id是否存在)
 | 
				
			||||||
 | 
					    async def send_personal_message(self, message: str, client_id: int):
 | 
				
			||||||
 | 
					        if client_id in self.active_connections:
 | 
				
			||||||
 | 
					            await self.active_connections[client_id].send_text(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 向所有的websocket连接发送消息
 | 
				
			||||||
 | 
					    async def broadcast(self, message: str):
 | 
				
			||||||
 | 
					        for client_id, ws in self.active_connections.items():
 | 
				
			||||||
 | 
					            await ws.send_text(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Task 基本模型
 | 
				
			||||||
 | 
					class Task(BaseModel):
 | 
				
			||||||
 | 
					    id: int
 | 
				
			||||||
 | 
					    name: str
 | 
				
			||||||
 | 
					    status: str
 | 
				
			||||||
 | 
					    created_at: datetime
 | 
				
			||||||
 | 
					    updated_at: datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 使用字典来存储Task任务
 | 
				
			||||||
 | 
					class TaskManager(object):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.tasks = {}
 | 
				
			||||||
 | 
					        # TOOD: 保持一个后台线程,定时检查任务的状态,并将任务的状态更新到数据中
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create(self, task: dict):
 | 
				
			||||||
 | 
					        task["id"] = str(uuid.uuid4())
 | 
				
			||||||
 | 
					        self.tasks[task["id"]] = task
 | 
				
			||||||
 | 
					        return task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, task_id: str):
 | 
				
			||||||
 | 
					        del self.tasks[task_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update(self, task_id, task: dict):
 | 
				
			||||||
 | 
					        self.tasks[task_id] = task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def query(self, task_id: str):
 | 
				
			||||||
 | 
					        return self.tasks[task_id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def query_all(self):
 | 
				
			||||||
 | 
					        return self.tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 使用字典来存储服务器池(使用腾讯云的API来管理服务器)
 | 
				
			||||||
 | 
					class ServerManager(object):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.servers = {}
 | 
				
			||||||
 | 
					        # 维护一个服务器池,每个服务器都有一个状态,状态有三种:空闲,运行中,异常
 | 
				
			||||||
 | 
					        # 如果服务器异常,需要将其从服务器池中删除
 | 
				
			||||||
 | 
					        # 如果服务器空闲,需要通知弹性伸缩服务将其删除
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 添加一个新的服务器(如何得知增加了新服务器? 主动发现? 被动发现? 使用腾讯云的API主动增加服务器)
 | 
				
			||||||
 | 
					        def add(self, server_name, server_info):
 | 
				
			||||||
 | 
					            self.servers[server_name] = server_info
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        def delete(self, server_name):
 | 
				
			||||||
 | 
					            del self.servers[server_name]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        def update(self, server_name, server_info):
 | 
				
			||||||
 | 
					            self.servers[server_name] = server_info
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        def query(self, server_name):
 | 
				
			||||||
 | 
					            return self.servers[server_name]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        def query_all(self):
 | 
				
			||||||
 | 
					            return self.servers
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
# 使用字典来存储Task任务
 | 
					 | 
				
			||||||
# 任务的状态有:未开始、进行中、已完成
 | 
					 | 
				
			||||||
# 任务的状态可以通过TaskManager来进行修改
 | 
					 | 
				
			||||||
# 任务的状态可以通过TaskManager来进行查询
 | 
					 | 
				
			||||||
# 任务的状态可以通过TaskManager来进行删除
 | 
					 | 
				
			||||||
# 任务的状态可以通过TaskManager来进行添加
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TaskManager(object):
 | 
					 | 
				
			||||||
    def __init__(self):
 | 
					 | 
				
			||||||
        self.tasks = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def add(self, task_name):
 | 
					 | 
				
			||||||
        self.tasks[task_name] = 'not started'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delete(self, task_name):
 | 
					 | 
				
			||||||
        del self.tasks[task_name]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update(self, task_name, status):
 | 
					 | 
				
			||||||
        self.tasks[task_name] = status
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def query(self, task_name):
 | 
					 | 
				
			||||||
        return self.tasks[task_name]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def query_all(self):
 | 
					 | 
				
			||||||
        return self.tasks
 | 
					 | 
				
			||||||
							
								
								
									
										29
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								main.py
									
									
									
									
									
								
							@@ -1,7 +1,8 @@
 | 
				
			|||||||
import uvicorn
 | 
					import uvicorn
 | 
				
			||||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, Depends, HTTPException
 | 
					from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, Depends, HTTPException
 | 
				
			||||||
from fastapi.responses import HTMLResponse
 | 
					from fastapi.responses import HTMLResponse
 | 
				
			||||||
import ConnectionManager
 | 
					from ObjectManager import ConnectionManager, TaskManager, ServerManager, Task
 | 
				
			||||||
 | 
					from typing import List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
@@ -55,8 +56,8 @@ app = FastAPI()
 | 
				
			|||||||
async def get():
 | 
					async def get():
 | 
				
			||||||
    return HTMLResponse(html)
 | 
					    return HTMLResponse(html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
manager = ConnectionManager.ConnectionManager()
 | 
					connection_manager = ConnectionManager()
 | 
				
			||||||
 | 
					task_manager = TaskManager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 接收客户端的websocket连接
 | 
					# 接收客户端的websocket连接
 | 
				
			||||||
@app.websocket("/ws/{client_id}")
 | 
					@app.websocket("/ws/{client_id}")
 | 
				
			||||||
@@ -67,16 +68,17 @@ async def websocket_endpoint(websocket: WebSocket, client_id: int):
 | 
				
			|||||||
    # if token is None:
 | 
					    # if token is None:
 | 
				
			||||||
    #     raise HTTPException(status_code=401, detail="Unauthorized")
 | 
					    #     raise HTTPException(status_code=401, detail="Unauthorized")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await manager.connect(websocket=websocket, client_id=client_id)
 | 
					    await connection_manager.connect(websocket=websocket, client_id=client_id)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
            data = await websocket.receive_text()
 | 
					            data = await websocket.receive_text()
 | 
				
			||||||
            await manager.send_personal_message(f"You wrote: {data}", client_id=client_id)
 | 
					            await connection_manager.send_personal_message(f"You wrote: {data}", client_id=client_id)
 | 
				
			||||||
            await manager.broadcast(f"Client #{client_id} says: {data}")
 | 
					            await connection_manager.broadcast(f"Client #{client_id} says: {data}")
 | 
				
			||||||
            # TODO: 处理客户端的请求变化(理论上并没有)
 | 
					            # TODO: 处理客户端的请求变化(理论上并没有)
 | 
				
			||||||
    except WebSocketDisconnect:
 | 
					    except WebSocketDisconnect:
 | 
				
			||||||
        manager.disconnect(websocket)
 | 
					        connection_manager.disconnect(client_id=client_id)
 | 
				
			||||||
        await manager.broadcast(f"Client #{client_id} left the chat")
 | 
					        await connection_manager.broadcast(f"Client #{client_id} left the chat")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 通知所有的ws客户端
 | 
					# 通知所有的ws客户端
 | 
				
			||||||
@app.post("/notify")
 | 
					@app.post("/notify")
 | 
				
			||||||
@@ -84,5 +86,16 @@ async def notify():
 | 
				
			|||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.get("/tasks", response_model=List[Task])
 | 
				
			||||||
 | 
					async def get_tasks():
 | 
				
			||||||
 | 
					    return task_manager.query_all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.post("/tasks", response_model=Task)
 | 
				
			||||||
 | 
					async def create_task():
 | 
				
			||||||
 | 
					    return task_manager.add({
 | 
				
			||||||
 | 
					        "name": "test",
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 维护一个任务队列, 任务队列中的任务会被分发给worker节点
 | 
					# 维护一个任务队列, 任务队列中的任务会被分发给worker节点
 | 
				
			||||||
# 任务状态变化时通知对应的客户端
 | 
					# 任务状态变化时通知对应的客户端
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										96
									
								
								tencent.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								tencent.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					import json
 | 
				
			||||||
 | 
					from tencentcloud.common import credential
 | 
				
			||||||
 | 
					from tencentcloud.common.profile.client_profile import ClientProfile
 | 
				
			||||||
 | 
					from tencentcloud.common.profile.http_profile import HttpProfile
 | 
				
			||||||
 | 
					from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
 | 
				
			||||||
 | 
					from tencentcloud.cvm.v20170312 import cvm_client, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 从腾讯云自动弹性伸缩
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					1. 通过腾讯云API创建一个服务器
 | 
				
			||||||
 | 
					2. 通过腾讯云API获取服务器的IP地址
 | 
				
			||||||
 | 
					3. 通过腾讯云API获取服务器的用户名和密码
 | 
				
			||||||
 | 
					4. 通过腾讯云API获取服务器的端口号
 | 
				
			||||||
 | 
					5. 通过腾讯云API获取服务器的状态
 | 
				
			||||||
 | 
					6. 通过腾讯云API删除一个服务器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 如果服务器闲置数大于两台,需要通知腾讯云API删除一台闲置服务器
 | 
				
			||||||
 | 
					2. 如果服务器负载全满,需要通知腾讯云API创建一台新的服务器
 | 
				
			||||||
 | 
					3. 如果服务器负载不全满,需要通知腾讯云API删除一台闲置服务器
 | 
				
			||||||
 | 
					4. 每天的早上9点到下午5点, 至少保留一台空闲服务器
 | 
				
			||||||
 | 
					5. 每天的晚上5点到早上9点, 移除所有空闲服务器
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    # 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
 | 
				
			||||||
 | 
					    # 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
 | 
				
			||||||
 | 
					    # 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
 | 
				
			||||||
 | 
					    cred = credential.Credential("AKIDgO0UrfO2b4mS6io7Yx9Yq1Pjz8AA4qUA", "jVBtV1SnprOviRK5teR7GC82thbTKqrv")
 | 
				
			||||||
 | 
					    # 实例化一个http选项,可选的,没有特殊需求可以跳过
 | 
				
			||||||
 | 
					    httpProfile = HttpProfile()
 | 
				
			||||||
 | 
					    httpProfile.endpoint = "cvm.ap-guangzhou.tencentcloudapi.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 实例化一个client选项,可选的,没有特殊需求可以跳过
 | 
				
			||||||
 | 
					    clientProfile = ClientProfile()
 | 
				
			||||||
 | 
					    clientProfile.httpProfile = httpProfile
 | 
				
			||||||
 | 
					    # 实例化要请求产品的client对象,clientProfile是可选的
 | 
				
			||||||
 | 
					    client = cvm_client.CvmClient(cred, "ap-guangzhou", clientProfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 实例化一个请求对象,每个接口都会对应一个request对象
 | 
				
			||||||
 | 
					    req = models.RunInstancesRequest()
 | 
				
			||||||
 | 
					    params = {
 | 
				
			||||||
 | 
					        "InstanceChargeType": "SPOTPAID",
 | 
				
			||||||
 | 
					        "DisableApiTermination": False,
 | 
				
			||||||
 | 
					        "Placement": {
 | 
				
			||||||
 | 
					            "Zone": "ap-guangzhou-6",
 | 
				
			||||||
 | 
					            "ProjectId": 0
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "InstanceMarketOptions": {
 | 
				
			||||||
 | 
					            "SpotOptions": {
 | 
				
			||||||
 | 
					                "MaxPrice": "1000"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "VirtualPrivateCloud": {
 | 
				
			||||||
 | 
					            "AsVpcGateway": False,
 | 
				
			||||||
 | 
					            "VpcId": "vpc-fyjby1gt",
 | 
				
			||||||
 | 
					            "SubnetId": "subnet-oqdeakts",
 | 
				
			||||||
 | 
					            "Ipv6AddressCount": 0
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "InstanceType": "S6.MEDIUM2",
 | 
				
			||||||
 | 
					        "ImageId": "img-eb30mz89",
 | 
				
			||||||
 | 
					        "SystemDisk": {
 | 
				
			||||||
 | 
					            "DiskSize": 50,
 | 
				
			||||||
 | 
					            "DiskType": "CLOUD_BSSD"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "InternetAccessible": {
 | 
				
			||||||
 | 
					            "InternetMaxBandwidthOut": 100,
 | 
				
			||||||
 | 
					            "PublicIpAssigned": True,
 | 
				
			||||||
 | 
					            "InternetChargeType": "TRAFFIC_POSTPAID_BY_HOUR"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "InstanceName": "未命名",
 | 
				
			||||||
 | 
					        "LoginSettings": {
 | 
				
			||||||
 | 
					            "KeyIds": [ "skey-672qeot7" ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "SecurityGroupIds": [ "sg-fkkd8qw9" ],
 | 
				
			||||||
 | 
					        "InstanceCount": 1,
 | 
				
			||||||
 | 
					        "EnhancedService": {
 | 
				
			||||||
 | 
					            "SecurityService": {
 | 
				
			||||||
 | 
					                "Enabled": True
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "MonitorService": {
 | 
				
			||||||
 | 
					                "Enabled": True
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "AutomationService": {
 | 
				
			||||||
 | 
					                "Enabled": True
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    req.from_json_string(json.dumps(params))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 返回的resp是一个RunInstancesResponse的实例,与请求对象对应
 | 
				
			||||||
 | 
					    resp = client.RunInstances(req)
 | 
				
			||||||
 | 
					    # 输出json格式的字符串回包
 | 
				
			||||||
 | 
					    print(resp.to_json_string())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					except TencentCloudSDKException as err:
 | 
				
			||||||
 | 
					    print(err)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user