调整项目公共内容,日志、文档基类和基础视图
1. 新增项目、机器相关模型和视图 2. 区服信息同步接口(同ops1,可接收batchQuery采集的信息)
This commit is contained in:
parent
0d771bf0cb
commit
d07ecbc497
10
app.py
10
app.py
|
@ -1,15 +1,25 @@
|
|||
import sys
|
||||
import os.path
|
||||
from logging.config import dictConfig
|
||||
|
||||
from flask import Flask
|
||||
from flask.logging import default_handler
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
|
||||
from database.mongodb import initialize_db
|
||||
from routes import blueprint_api
|
||||
from settings.dev import LOGGING
|
||||
|
||||
|
||||
# 日志配置
|
||||
dictConfig(LOGGING)
|
||||
|
||||
# app 实例,移除默认日志,加载配置文件
|
||||
app = Flask(__name__)
|
||||
app.logger.removeHandler(default_handler)
|
||||
app.config.from_pyfile("settings/dev.py")
|
||||
|
||||
# 初始化数据库连接
|
||||
initialize_db(app)
|
||||
|
||||
# 注册蓝图
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
from asset.models import Host
|
||||
from project.models import Project, Channel, Server, Version
|
||||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger('flask.app.script')
|
||||
|
||||
projects = [
|
||||
{
|
||||
"name": "ts01/cn",
|
||||
"id": 1,
|
||||
"desc": "测试",
|
||||
"domain": "www.baidu.com",
|
||||
"www_ip": "127.0.0.1",
|
||||
"ops_ip": "10.2.2.10",
|
||||
"transfer_ip": "10.2.2.10",
|
||||
"webhook": "",
|
||||
"kw": ""
|
||||
},
|
||||
{
|
||||
"name": "ab01/cn",
|
||||
"id": 2,
|
||||
"desc": "测试ab01",
|
||||
"domain": "ab01.www.baidu.com",
|
||||
"www_ip": "127.0.0.1",
|
||||
"ops_ip": "10.2.2.11",
|
||||
"transfer_ip": "10.2.2.13",
|
||||
"webhook": "",
|
||||
"kw": ""
|
||||
},
|
||||
{
|
||||
"name": "aa11/tw",
|
||||
"id": 3,
|
||||
"desc": "1212",
|
||||
"domain": "www.baidu.com",
|
||||
"www_ip": "127.0.0.1",
|
||||
"ops_ip": "11.22.33.44",
|
||||
"transfer_ip": "11.22.33.45",
|
||||
"webhook": "",
|
||||
"kw": ""
|
||||
},
|
||||
{
|
||||
"name": "qq88/cn",
|
||||
"id": 4,
|
||||
"desc": "qq88/cn",
|
||||
"domain": "qq88.com",
|
||||
"www_ip": "127.0.0.1",
|
||||
"ops_ip": "10.2.2.10",
|
||||
"transfer_ip": "10.2.2.11",
|
||||
"webhook": "",
|
||||
"kw": ""
|
||||
},
|
||||
{
|
||||
"name": "ug41/cn",
|
||||
"id": 5,
|
||||
"desc": "ug41",
|
||||
"domain": "ug41.huanyuantech.com",
|
||||
"www_ip": "127.0.0.1",
|
||||
"ops_ip": "127.0.0.1",
|
||||
"transfer_ip": "127.0.0.1",
|
||||
"webhook": "",
|
||||
"kw": "ug41-cn"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
# def sync_project():
|
||||
# for p in projects:
|
||||
# proj = p
|
||||
# name = proj.pop("name")
|
||||
# game, fork = name.split("/")
|
||||
# proj["name"] = game
|
||||
# proj["fork"] = fork
|
||||
# proj.pop("id")
|
||||
# # 字典中缺少的值会是None,字段必须null=True
|
||||
# obj = models.Project(**proj)
|
||||
# obj.save()
|
||||
|
||||
|
||||
def sync_server_info():
|
||||
project = Project.objects(name="ug41", fork="cn").first()
|
||||
info = [{"ip": "10.2.2.10", "spid": "abo", "num": 1, "server_version": "2021100801", "cfg_version": "8616", "admin_version": "2021062801", "lua_version": "122", "flag": "2", "status": "0", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 1, "server_version": "2021100801", "cfg_version": "7950", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 2, "server_version": "2021100801", "cfg_version": "2014", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 3, "server_version": "2021100801", "cfg_version": "7003", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 4, "server_version": "2021100801", "cfg_version": "8406", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 5, "server_version": "2021100801", "cfg_version": "17399", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}, {"ip": "10.2.2.11", "spid": "dev", "num": 6, "server_version": "2021100801", "cfg_version": "8375", "admin_version": "2021062801", "lua_version": "122", "flag": "0", "status": "1", "port": 0}]
|
||||
for srv in info:
|
||||
ip = srv.get("ip")
|
||||
num = srv.get("num")
|
||||
spid = srv.get("spid")
|
||||
port = srv.get("port", 0)
|
||||
# 内嵌的版本字段
|
||||
version = Version()
|
||||
version.admin = srv.get("admin_version", "")
|
||||
version.server = srv.get("server_version", "")
|
||||
version.config = srv.get("cfg_version", "")
|
||||
version.lua = srv.get("lua_version", "")
|
||||
version.bin = srv.get("bin_version", "")
|
||||
version.sql = srv.get("sql_version", "")
|
||||
state = srv.get("status", "1")
|
||||
if srv.get("flag", "0") == "2":
|
||||
status = "closed"
|
||||
else:
|
||||
status = "running" if state == "1" else "error"
|
||||
|
||||
try:
|
||||
host = Host.objects(public_ip=ip).first()
|
||||
if not host:
|
||||
host = Host(public_ip=ip)
|
||||
host.save()
|
||||
|
||||
channel = Channel.objects(project=project, spid=spid).first()
|
||||
if not channel:
|
||||
channel = Channel(project=project, spid=spid)
|
||||
channel.save()
|
||||
|
||||
# 更新、创建的参数
|
||||
defaults = dict(host=host, version=version, port=port, status=status)
|
||||
srv_obj = Server.objects(num=num, channel=channel).first()
|
||||
if not srv_obj: # 创建
|
||||
srv_obj = Server(num=num, channel=channel, **defaults)
|
||||
srv_obj.save()
|
||||
logger.info(f"创建 {spid}_{num} 区服信息成功")
|
||||
continue
|
||||
# 更新对象
|
||||
srv_obj.update(**defaults)
|
||||
srv_obj.save()
|
||||
logger.info(f"更新 {spid}_{num} 区服信息成功")
|
||||
except:
|
||||
logger.exception("同步区服出错")
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# sync_project()
|
||||
sync_server_info()
|
|
@ -1,5 +1,47 @@
|
|||
import os.path
|
||||
|
||||
# 项目目录
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# mongodb 地址
|
||||
MONGODB_SETTINGS = {
|
||||
'host': 'mongodb://admin:111111@10.2.2.10:27017/ops_api?authSource=admin',
|
||||
}
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '%(asctime)s %(levelname)s %(module)s:%(funcName)s %(process)d %(thread)d %(message)s'
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(message)s'
|
||||
},
|
||||
},
|
||||
'filters': {
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'simple'
|
||||
},
|
||||
'file_app': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(os.path.dirname(BASE_DIR), 'logs/app.log'),
|
||||
'encoding': 'utf-8',
|
||||
'maxBytes': 1024 * 1024 * 5,
|
||||
'backupCount': 5,
|
||||
'formatter': 'verbose'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'root': {
|
||||
'handlers': ['file_app'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
"""
|
||||
asset marshal fields
|
||||
"""
|
||||
|
||||
from flask_restful import fields
|
||||
|
||||
|
||||
HostFields = {
|
||||
"id": fields.String,
|
||||
"public_ip": fields.String,
|
||||
"private_ip": fields.String,
|
||||
"minion_id": fields.String,
|
||||
"weights": fields.Integer,
|
||||
"cpu_num": fields.Integer,
|
||||
"cpu_core": fields.Integer,
|
||||
"memory": fields.Integer,
|
||||
"tags": fields.List(fields.String),
|
||||
"labels": fields.Raw,
|
||||
"created": fields.DateTime,
|
||||
}
|
||||
|
||||
HostSimpleFields = {
|
||||
"id": fields.String,
|
||||
"public_ip": fields.String,
|
||||
"private_ip": fields.String,
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import mongoengine as mongo
|
||||
|
||||
from common.document import DocumentBase
|
||||
from common.validator import is_ipaddr
|
||||
|
||||
|
||||
class Host(DocumentBase):
|
||||
|
||||
# STATUS = {
|
||||
# "no": ""
|
||||
# }
|
||||
|
||||
public_ip = mongo.StringField(max_length=64, required=True, unique=True, validation=is_ipaddr)
|
||||
private_ip = mongo.StringField(max_length=64, default="")
|
||||
minion_id = mongo.StringField(max_length=64, default="") # 需要唯一,先留空
|
||||
weights = mongo.IntField(default=40)
|
||||
# status = mongo.StringField()
|
||||
# spec = mongo.EmbeddedDocumentField(Spec)
|
||||
|
||||
cpu_num = mongo.IntField(default=1) # cpu物理个数
|
||||
cpu_core = mongo.IntField(default=1) # 每个cpu的核心数
|
||||
memory = mongo.IntField(default=0) # 内存大小,单位GB
|
||||
|
||||
# 标记和标签
|
||||
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
|
||||
labels = mongo.DictField(default=dict)
|
||||
|
||||
created = mongo.DateTimeField()
|
|
@ -0,0 +1,13 @@
|
|||
from flask import Blueprint
|
||||
from flask_restful import Api
|
||||
|
||||
from asset import views
|
||||
|
||||
|
||||
# 当前app的蓝图,以app名为前缀
|
||||
asset = Blueprint('asset', __name__, url_prefix="/asset")
|
||||
|
||||
# 增加路由
|
||||
api = Api(asset)
|
||||
api.add_resource(views.HostViews, '/host/', endpoint="host")
|
||||
api.add_resource(views.HostDetailViews, '/host/<string:pk>/', endpoint="host-detail")
|
|
@ -0,0 +1,14 @@
|
|||
from asset import fields
|
||||
from asset.models import Host
|
||||
|
||||
from common.views import ListCreateViewSet, DetailViewSet
|
||||
|
||||
|
||||
class HostViews(ListCreateViewSet):
|
||||
model = Host
|
||||
fields = fields.HostFields
|
||||
|
||||
|
||||
class HostDetailViews(DetailViewSet):
|
||||
model = Host
|
||||
fields = fields.HostFields
|
|
@ -0,0 +1,44 @@
|
|||
"""
|
||||
mongo 文档相关封装
|
||||
"""
|
||||
|
||||
from flask_mongoengine import Document, BaseQuerySet
|
||||
|
||||
|
||||
class DocumentBase(Document):
|
||||
"""自定义的文档处理方法扩展
|
||||
注意此类必须设置meta如下,参考 `flask_mongoengine.Document`:
|
||||
{"abstract": True, "queryset_class": BaseQuerySet}
|
||||
"""
|
||||
|
||||
meta = {"abstract": True, "queryset_class": BaseQuerySet}
|
||||
|
||||
@classmethod
|
||||
def get_or_create(cls, defaults: dict = None, **kwargs):
|
||||
"""获取或创建一个对象,必须传好参数,确保正确且唯一,需要外部捕捉异常
|
||||
:param defaults: 创建参数
|
||||
:param kwargs: 对象查找参数
|
||||
"""
|
||||
created = False
|
||||
obj = cls.objects(**kwargs).first()
|
||||
if not obj:
|
||||
obj = cls(**defaults)
|
||||
obj.save()
|
||||
created = True
|
||||
return obj, created
|
||||
|
||||
@classmethod
|
||||
def update_or_create(cls, defaults: dict = None, **kwargs):
|
||||
"""更新或创建对象
|
||||
:param defaults: 创建、更新参数
|
||||
:param kwargs: 对象查找参数
|
||||
"""
|
||||
created = False
|
||||
obj = cls.objects(**kwargs).first()
|
||||
if not obj:
|
||||
obj = cls(**defaults)
|
||||
obj.save()
|
||||
created = True
|
||||
else:
|
||||
obj.update(**defaults)
|
||||
return obj, created
|
|
@ -0,0 +1,15 @@
|
|||
import ipaddress
|
||||
import mongoengine as mongo
|
||||
|
||||
|
||||
def isalnum(string: str):
|
||||
"""数字、字母验证器"""
|
||||
if not string.isalnum():
|
||||
raise mongo.ValidationError('The value must be a combination of letters and numbers')
|
||||
|
||||
|
||||
def is_ipaddr(ip):
|
||||
try:
|
||||
ipaddress.ip_address(ip)
|
||||
except:
|
||||
raise mongo.ValidationError('The value must be a ip address')
|
|
@ -1,14 +1,14 @@
|
|||
from flask_restful import abort, Resource, marshal, fields
|
||||
from flask_restful import abort, Resource, marshal, fields, reqparse
|
||||
|
||||
|
||||
class ModelViewBase(Resource):
|
||||
model = None
|
||||
fields = {}
|
||||
request_parse = None
|
||||
request_parse: reqparse.RequestParser = None
|
||||
|
||||
def get_object(self, pk):
|
||||
try:
|
||||
return self.model.objects.get_or_404(id=pk)
|
||||
return self.model.objects(id=pk).first_or_404(message="resource not found")
|
||||
except:
|
||||
abort(404, msg=f"resource '{pk}' not found")
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
from game.views import Server
|
||||
from flask import Blueprint
|
||||
from flask_restful import Api
|
||||
|
||||
# 当前app的蓝图,以app名为前缀
|
||||
game = Blueprint('game', __name__, url_prefix="/game")
|
||||
|
||||
# 增加路由
|
||||
api = Api(game)
|
||||
api.add_resource(Server, '/server/', endpoint="server")
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
from flask_restful import Resource
|
||||
|
||||
|
||||
class Server(Resource):
|
||||
""""""
|
||||
def get(self):
|
||||
return {"msg": "ok", "method": "get"}
|
||||
|
||||
def post(self):
|
||||
return {"msg": "ok", "method": "post"}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
"""
|
||||
project marshal fields
|
||||
"""
|
||||
|
||||
from flask_restful import fields
|
||||
from asset.fields import HostSimpleFields
|
||||
|
||||
ProjectFields = {
|
||||
"id": fields.String,
|
||||
"name": fields.String,
|
||||
"fork": fields.String,
|
||||
"domain": fields.String,
|
||||
"www_ip": fields.String,
|
||||
"ops_ip": fields.String,
|
||||
"transfer_ip": fields.String,
|
||||
"webhook": fields.String,
|
||||
"kw": fields.String,
|
||||
"desc": fields.String,
|
||||
"repository": fields.String,
|
||||
"tags": fields.List(fields.String),
|
||||
"labels": fields.Raw,
|
||||
}
|
||||
|
||||
ProjectSimpleField = {
|
||||
"id": fields.String,
|
||||
"name": fields.String,
|
||||
"fork": fields.String,
|
||||
"domain": fields.String,
|
||||
}
|
||||
|
||||
VersionFields = {
|
||||
"admin": fields.String,
|
||||
"server": fields.String,
|
||||
"config": fields.String,
|
||||
"lua": fields.String,
|
||||
"sql": fields.String,
|
||||
"bin": fields.String,
|
||||
}
|
||||
|
||||
ChannelFields = {
|
||||
"id": fields.String,
|
||||
"project": fields.Nested(ProjectSimpleField),
|
||||
"name": fields.String,
|
||||
"spid": fields.String,
|
||||
"version": fields.Nested(VersionFields),
|
||||
"repository": fields.String,
|
||||
"branch": fields.String,
|
||||
"tags": fields.List(fields.String), # List 必须指明类型
|
||||
"labels": fields.Raw,
|
||||
}
|
||||
|
||||
ChannelSimpleFields = {
|
||||
"id": fields.String,
|
||||
"spid": fields.String,
|
||||
"project": fields.Nested(ProjectSimpleField),
|
||||
}
|
||||
|
||||
ServerFields = {
|
||||
"id": fields.String,
|
||||
"num": fields.Integer,
|
||||
"channel": fields.Nested(ChannelSimpleFields),
|
||||
"status": fields.String,
|
||||
"host": fields.Nested(HostSimpleFields),
|
||||
"domain": fields.String,
|
||||
"port": fields.Integer,
|
||||
"version": fields.Nested(VersionFields),
|
||||
"weight": fields.Integer,
|
||||
"slot": fields.Integer,
|
||||
"tag": fields.List(fields.String),
|
||||
"labels": fields.Raw,
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
import mongoengine as mongo
|
||||
from common.document import DocumentBase
|
||||
|
||||
from common.validator import isalnum
|
||||
|
||||
from asset.models import Host
|
||||
|
||||
|
||||
class Project(DocumentBase):
|
||||
"""项目模型定义"""
|
||||
# 四位字符,字母、数字组合,name、fork组合必须是唯一
|
||||
name = mongo.StringField(max_length=4, min_length=4, required=True, unique_with="fork", validation=isalnum)
|
||||
fork = mongo.StringField(max_length=2, min_length=2, required=True, validation=isalnum)
|
||||
domain = mongo.StringField(max_length=128, required=False)
|
||||
www_ip = mongo.StringField(max_length=64, required=False)
|
||||
ops_ip = mongo.StringField(max_length=64, required=False)
|
||||
transfer_ip = mongo.StringField(max_length=64, required=False)
|
||||
webhook = mongo.StringField(max_length=256, required=False)
|
||||
kw = mongo.StringField(max_length=32, required=False)
|
||||
desc = mongo.StringField(max_length=256, default="")
|
||||
# 项目的代码仓库地址
|
||||
repository = mongo.StringField("仓库", max_length=256, default="", help_text="仓库地址", null=True)
|
||||
# 标记和标签
|
||||
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
|
||||
labels = mongo.DictField(default=dict)
|
||||
|
||||
def fullname(self):
|
||||
return f"{self.name}/{self.fork}"
|
||||
|
||||
|
||||
class Version(mongo.EmbeddedDocument):
|
||||
"""版本信息"""
|
||||
admin = mongo.StringField(max_length=32, required=False, default="")
|
||||
|
||||
server = mongo.StringField(max_length=32, required=False, default="")
|
||||
config = mongo.StringField(max_length=32, required=False, default="")
|
||||
lua = mongo.StringField(max_length=32, required=False, default="")
|
||||
sql = mongo.StringField(max_length=32, required=False, default="")
|
||||
bin = mongo.StringField(max_length=32, required=False, default="")
|
||||
|
||||
|
||||
class Channel(DocumentBase):
|
||||
"""渠道"""
|
||||
# spid项目内唯一
|
||||
project = mongo.ReferenceField(Project, reverse_delete_rule=mongo.NULLIFY)
|
||||
name = mongo.StringField(max_length=32, default="")
|
||||
spid = mongo.StringField(max_length=3, min_length=3, required=True, unique_with="project", validation=isalnum)
|
||||
version = mongo.EmbeddedDocumentField(Version) # 缺失时获取对象的此字段为 None
|
||||
|
||||
# 项目的代码仓库地址
|
||||
repository = mongo.StringField(max_length=256, default="")
|
||||
branch = mongo.StringField(max_length=32)
|
||||
|
||||
# 标记和标签
|
||||
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
|
||||
labels = mongo.DictField(default=dict)
|
||||
|
||||
created = mongo.DateTimeField()
|
||||
|
||||
|
||||
class Server(DocumentBase):
|
||||
"""服务"""
|
||||
|
||||
STATUS = {
|
||||
"prepare": "预备",
|
||||
"stopped": "停止",
|
||||
"running": "运行中",
|
||||
"closed": "关服",
|
||||
"maintain": "维护",
|
||||
"error": "异常"
|
||||
}
|
||||
|
||||
num = mongo.IntField(required=True, unique_with="channel")
|
||||
channel = mongo.ReferenceField(Channel)
|
||||
status = mongo.StringField(max_length=12, choices=STATUS.keys(), required=True, default="running")
|
||||
|
||||
# 机器字段,TODO 先允许为空
|
||||
host = mongo.ReferenceField(Host, null=True)
|
||||
domain = mongo.StringField(max_length=128, required=False)
|
||||
port = mongo.IntField()
|
||||
version = mongo.EmbeddedDocumentField(Version)
|
||||
weight = mongo.IntField(default=1)
|
||||
slot = mongo.IntField(default=0)
|
||||
|
||||
# 标记和标签
|
||||
tags = mongo.ListField(mongo.StringField(), default=list) # tags 默认是空列表
|
||||
labels = mongo.DictField(default=dict)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
from flask import Blueprint
|
||||
from flask_restful import Api
|
||||
|
||||
from project import views
|
||||
|
||||
|
||||
# 当前app的蓝图,以app名为前缀
|
||||
project = Blueprint('project', __name__, url_prefix="/project")
|
||||
|
||||
# 增加路由
|
||||
api = Api(project)
|
||||
# 项目模型的视图
|
||||
api.add_resource(views.ProjectViews, '/item/', endpoint="project")
|
||||
api.add_resource(views.ProjectDetailViews, '/item/<string:pk>/', endpoint="project-detail")
|
||||
|
||||
# 渠道模型视图
|
||||
api.add_resource(views.ChannelViews, '/channel/', endpoint="channel")
|
||||
api.add_resource(views.ChannelDetailViews, '/channel/<string:pk>/', endpoint="channel-detail")
|
||||
|
||||
# 区服模型视图
|
||||
api.add_resource(views.ServerViews, '/server/', endpoint="server")
|
||||
api.add_resource(views.ServerDetailView, '/server/<string:pk>/', endpoint="server-detail")
|
||||
# 区服信息同步接口,更新区服信息
|
||||
api.add_resource(views.ServerSyncView, '/server/sync/', endpoint="server-sync")
|
|
@ -0,0 +1,137 @@
|
|||
import datetime
|
||||
|
||||
from flask import current_app as app
|
||||
from flask_restful import reqparse, abort
|
||||
|
||||
from asset.models import Host
|
||||
from project import fields
|
||||
from project.models import Project, Channel, Server, Version
|
||||
from common.views import ListMixin, CreateMixin, ListCreateViewSet, DetailViewSet
|
||||
|
||||
|
||||
class ProjectViews(ListMixin, CreateMixin):
|
||||
model = Project
|
||||
fields = fields.ProjectFields
|
||||
|
||||
|
||||
class ProjectDetailViews(DetailViewSet):
|
||||
model = Project
|
||||
fields = fields.ProjectFields
|
||||
|
||||
|
||||
class ChannelViews(ListCreateViewSet):
|
||||
model = Channel
|
||||
fields = fields.ChannelFields
|
||||
|
||||
|
||||
class ChannelDetailViews(DetailViewSet):
|
||||
model = Channel
|
||||
fields = fields.ChannelFields
|
||||
|
||||
|
||||
class ServerViews(ListCreateViewSet):
|
||||
model = Server
|
||||
fields = fields.ServerFields
|
||||
|
||||
|
||||
class ServerDetailView(DetailViewSet):
|
||||
model = Server
|
||||
fields = fields.ServerFields
|
||||
|
||||
|
||||
class ServerSyncView(CreateMixin):
|
||||
"""同步区服信息,由 `batchQuery` 程序发送采集内容,此视图更新保存"""
|
||||
model = Server
|
||||
fields = fields.ServerFields
|
||||
project: Project = None
|
||||
|
||||
def __init__(self):
|
||||
# 参数定义,json来源
|
||||
self.request_parse = reqparse.RequestParser()
|
||||
self.request_parse.add_argument("project", type=str, required=True, location='json')
|
||||
self.request_parse.add_argument("fork", type=str, required=True, location='json')
|
||||
self.request_parse.add_argument("count", type=int, required=True, location='json')
|
||||
self.request_parse.add_argument("data", type=list, required=True, location='json')
|
||||
|
||||
def get_project(self, args):
|
||||
proj = args["project"]
|
||||
fork = args["fork"]
|
||||
self.project = Project.objects(name=proj, fork=fork).first_or_404(message="project not found")
|
||||
|
||||
@classmethod
|
||||
def parse_version(cls, srv: dict):
|
||||
"""解析版本"""
|
||||
version = Version()
|
||||
version.admin = srv.get("admin_version", "")
|
||||
version.server = srv.get("server_version", "")
|
||||
version.config = srv.get("cfg_version", "")
|
||||
version.lua = srv.get("lua_version", "")
|
||||
version.bin = srv.get("bin_version", "")
|
||||
version.sql = srv.get("sql_version", "")
|
||||
return version
|
||||
|
||||
@classmethod
|
||||
def parse_status(cls, srv: dict):
|
||||
"""解析 flag 和 status 值,据此判断返回区服的状态"""
|
||||
state = srv.get("status", "1")
|
||||
if srv.get("flag", "0") == "2":
|
||||
status = "closed"
|
||||
else:
|
||||
status = "running" if state == "1" else "error"
|
||||
return status
|
||||
|
||||
def post(self):
|
||||
"""同步区服信息,接收 json 数据"""
|
||||
# 校验参数
|
||||
args = self.request_parse.parse_args()
|
||||
self.get_project(args)
|
||||
|
||||
count = args["count"]
|
||||
data = args["data"]
|
||||
|
||||
if count != len(data):
|
||||
abort(400, msg="quantity mismatch", code=1001)
|
||||
|
||||
hosts = {}
|
||||
channels = {}
|
||||
errors = []
|
||||
for srv in data:
|
||||
ip = srv.get("ip")
|
||||
num = srv.get("num")
|
||||
spid = srv.get("spid")
|
||||
port = srv.get("port", 0)
|
||||
# 内嵌的版本字段
|
||||
version = self.parse_version(srv)
|
||||
status = self.parse_status(srv)
|
||||
host = hosts.get(ip)
|
||||
channel = channels.get(spid)
|
||||
|
||||
try:
|
||||
if not host:
|
||||
hostObj, _ = Host.get_or_create(
|
||||
public_ip=ip, defaults=dict(public_ip=ip, created=datetime.datetime.now()))
|
||||
host = hostObj.id
|
||||
hosts[ip] = hostObj.id
|
||||
if not channel:
|
||||
channelObj, _ = Channel.get_or_create(
|
||||
project=self.project, spid=spid, defaults=dict(project=self.project, spid=spid))
|
||||
channel = channelObj.id
|
||||
channels[spid] = channelObj.id
|
||||
|
||||
# 更新、创建的参数
|
||||
defaults = dict(num=num, channel=channel, host=host, version=version, port=port, status=status)
|
||||
obj, created = Server.update_or_create(defaults=defaults, num=num, channel=channel)
|
||||
if created: # 创建
|
||||
app.logger.debug(f"创建 {spid}_{num} 区服信息成功")
|
||||
continue
|
||||
# 更新对象日志
|
||||
app.logger.debug(f"更新 {spid}_{num} 区服信息成功")
|
||||
except:
|
||||
app.logger.exception("同步区服出错")
|
||||
errors.append(f"{spid}_s{num}")
|
||||
continue
|
||||
|
||||
if errors:
|
||||
return {"msg": "有区服同步出错!", "code": 1020, "errors": errors}
|
||||
|
||||
return {"msg": "ok", "code": 1000}
|
|
@ -1,9 +1,10 @@
|
|||
from flask import Blueprint
|
||||
from game.routes import game
|
||||
from project.routes import project
|
||||
from asset.routes import asset
|
||||
|
||||
|
||||
blueprint_api = Blueprint('api-main', __name__, url_prefix='/api')
|
||||
|
||||
# 注册子蓝图,嵌套
|
||||
blueprint_api.register_blueprint(game)
|
||||
|
||||
blueprint_api.register_blueprint(asset)
|
||||
blueprint_api.register_blueprint(project)
|
||||
|
|
Loading…
Reference in New Issue