6 网站架构---mongo使用

本文介绍了如何在网站架构中使用MongoDB,包括在models_mongo.py中创建数据库、集合和Model,通过ik_file_view.py定义HTTP接口,并在app/__init__.py中配置Flask启动时初始化MongoDB并注册蓝图。
摘要由CSDN通过智能技术生成

models_mongo.py:创建数据库、集合、model

# coding=utf-8
import os
import uuid
import magic
import urllib
from datetime import datetime
import cropresize2
import short_url
from PIL import Image
from flask import abort, request
from werkzeug.utils import cached_property
from mongoengine import (
    Document as BaseDocument, connect, ValidationError, DoesNotExist,
    QuerySet, MultipleObjectsReturned, IntField, DateTimeField, StringField,
    SequenceField)
from app.ik_global import ik_global
from app.utils.mimes import IMAGE_MIMES, AUDIO_MIMES, VIDEO_MIMES
from app.utils.ik_util import get_file_md5, get_file_path
from config import Config
# ik_global.Logger.info("MONGO_DB_HOST-------------> {}".format(Config.MONGO_DB_HOST))

connect(Config.MONGO_DB_NAME, host=Config.MONGO_DB_HOST, port=int(Config.MONGO_DB_PORT))


class BaseQuerySet(QuerySet):
    def get_or_404(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (MultipleObjectsReturned, DoesNotExist, ValidationError):
            abort(404)


class Document(BaseDocument):
    meta = {'abstract': True,
            'queryset_class': BaseQuerySet
            }


class PasteFile(Document):
    id = SequenceField(primary_key=True)
    filename = StringField(max_length=5000, null=False)
    filehash = StringField(max_length=128, null=False, unique=True)
    filemd5 = StringField(max_length=128, null=False, unique=True)
    uploadtime = DateTimeField(null=False)
    mimetype = StringField(max_length=128, null=False)
    size = IntField(null=False)
    meta = {'collection': 'paste_file'}  # 自定义集合的名字

    def __init__(self, filename='', mimetype='application/octet-stream',
                 size=0, filehash=None, filemd5=None, *args, **kwargs):
        # 初始化父类的__init__方法
        super(PasteFile, self).__init__(filename=filename, mimetype=mimetype,
                                        size=size, filehash=filehash,
                                        filemd5=filemd5, *args, **kwargs)
        self.uploadtime = datetime.now()
        self.mimetype = mimetype
        self.size = int(size)
        self.filehash = filehash if filehash else self._hash_filename(filename)
        self.filename = filename if filename else self.filehash
        self.filemd5 = filemd5

    @staticmethod
    def _hash_filename(filename):
        _, _, suffix = filename.rpartition('.')
        return '%s.%s' % (uuid.uuid4().hex, suffix)

    @cached_property
    def symlink(self):
        return short_url.encode_url(self.id)

    @classmethod
    def get_by_symlink(cls, symlink, code=404):
        id = short_url.decode_url(symlink)
        return cls.objects.get_or_404(id=id)

    @classmethod
    def get_by_filehash(cls, filehash, code=404):
        return cls.objects.get_or_404(filehash=filehash)

    @classmethod
    def get_by_md5(cls, filemd5):
        rs = cls.objects(filemd5=filemd5)
        return rs[0] if rs else None

    @classmethod
    def create_by_upload_file(cls, uploaded_file):
        ik_global.Logger.info("uploaded_file----> {} {} {}".format(uploaded_file,
                                                   uploaded_file.filename, uploaded_file.mimetype))
        rst = cls(uploaded_file.filename, uploaded_file.mimetype, 0)
        ik_global.Logger.info("rst.path----> {}".format(rst.path))
        uploaded_file.save(rst.path)
        with open(rst.path, "rb") as f:
            filemd5 = get_file_md5(f)
            uploaded_file = cls.get_by_md5(filemd5)
            if uploaded_file:
                os.remove(rst.path)
                return uploaded_file
        filestat = os.stat(rst.path)
        rst.size = filestat.st_size
        rst.filemd5 = filemd5
        return rst

    @classmethod
    def create_by_old_paste(cls, filehash):
        filepath = get_file_path(filehash)
        mimetype = magic.from_file(filepath, mime=True)
        filestat = os.stat(filepath)
        size = filestat.st_size

        rst = cls(filehash, mimetype, size, filehash=filehash)
        return rst

    @property
    def path(self):
        return get_file_path(self.filehash)

    def get_url(self, subtype, is_symlink=False):
        hash_or_link = self.symlink if is_symlink else self.filehash
        return 'http://{host}/{subtype}/{hash_or_link}'.format(
            subtype=subtype, host=request.host, hash_or_link=hash_or_link)

    @property
    def url_i(self):
        return self.get_url('i')

    @property
    def url_p(self):
        return self.get_url('p')

    @property
    def url_s(self):
        return self.get_url('s', is_symlink=True)

    @property
    def url_d(self):
        return self.get_url('d')

    @property
    def image_size(self):
        if self.is_image:
            im = Image.open(self.path)
            return im.size
        return (0, 0)

    @property
    def quoteurl(self):
        return urllib.parse.quote(self.url_i)

    @classmethod
    def rsize(cls, old_paste, weight, height):
        assert old_paste.is_image, TypeError('Unsupported Image Type.')

        img = cropresize2.crop_resize(
            Image.open(old_paste.path), (int(weight), int(height)))

        rst = cls(old_paste.filename, old_paste.mimetype, 0)
        img.save(rst.path)
        filestat = os.stat(rst.path)
        rst.size = filestat.st_size
        return rst

    @property
    def is_image(self):
        return self.mimetype in IMAGE_MIMES

    @property
    def is_audio(self):
        return self.mimetype in AUDIO_MIMES

    @property
    def is_video(self):
        return self.mimetype in VIDEO_MIMES

    @property
    def is_pdf(self):
        return self.mimetype == 'application/pdf'

    @property
    def type(self):
        for t in ('image', 'pdf', 'video', 'audio'):
            if getattr(self, 'is_' + t):
                return t
        return 'binary'

ik_file_view.py:定义http接口

import logging
import os
import time
from datetime import datetime
from app.comm import ik_comm
import ipaddress
from flask import abort, request, jsonify, redirect, send_file
from flask_jwt import jwt_required, current_identity
from werkzeug.contrib.cache import SimpleCache
from flask import jsonify
import json
from app.ikdb.model.models_mongo import PasteFile
from app.utils.ik_util import get_file_path, humanize_bytes
from app.utils.status_code import err_resp_json_make, FAIL, succ_resp_json_make
# from app.vpp.vpp import Pttool
from flask import Blueprint
ONE_MONTH = 60 * 60 * 24 * 30

bp = Blueprint('file', __name__,url_prefix="/file")


@bp.route('/rsize/<img_hash>')
def rsize(img_hash):
    w = request.args['w']
    h = request.args['h']

    old_paste = PasteFile.get_by_filehash(img_hash)
    new_paste = PasteFile.rsize(old_paste, w, h)

    return new_paste.url_i


@bp.route('/download/<filehash>', methods=['GET'])
def download(filehash):
    paste_file = PasteFile.get_by_filehash(filehash)

    return send_file(open(paste_file.path, 'rb'),
                     mimetype='application/octet-stream',
                     cache_timeout=ONE_MONTH,
                     as_attachment=True,
                     attachment_filename=paste_file.filename)


@bp.route('/upload', methods=['POST'])
def index():
    if request.method == 'POST':
        uploaded_file = request.files['file'] # werkzeug.datastructures.FileStorage
        w = request.form.get('w')
        h = request.form.get('h')
        if not uploaded_file:
            return abort(400)

        if w and h:
            paste_file = PasteFile.rsize(uploaded_file, w, h)
        else:
            paste_file = PasteFile.create_by_upload_file(uploaded_file)
        paste_file.save() #保存到db

        return jsonify({
            'url_d': paste_file.url_d,
            'url_i': paste_file.url_i,
            'url_s': paste_file.url_s,
            'url_p': paste_file.url_p,
            'filename': paste_file.filename,
            'size': humanize_bytes(paste_file.size),
            'time': str(paste_file.uploadtime),
            'type': paste_file.type,
            'quoteurl': paste_file.quoteurl
        })
    # return render_template('index.html', **locals())
    return err_resp_json_make(FAIL, extra_errmsg="upload fail")


@bp.route('/j', methods=['POST'])
def j():
    uploaded_file = request.files['file']

    if uploaded_file:
        paste_file = PasteFile.create_by_upload_file(uploaded_file)
        paste_file.save()
        width, height = paste_file.image_size

        return jsonify({
            'url': paste_file.url_i,
            'short_url': paste_file.url_s,
            'origin_filename': paste_file.filename,
            'hash': paste_file.filehash,
            'width': width,
            'height': height
        })

    return abort(400)


@bp.route('/preview/<filehash>')
def preview(filehash):
    paste_file = PasteFile.get_by_filehash(filehash)

    if not paste_file:
        filepath = get_file_path(filehash)
        if not(os.path.exists(filepath) and (not os.path.islink(filepath))):
            return abort(404)

        paste_file = PasteFile.create_by_old_paste(filehash)
        paste_file.save()

    # return render_template('success.html', p=paste_file)
    return succ_resp_json_make(extra_errmsg="preview success")


@bp.route('/s/<symlink>')
def s(symlink):
    paste_file = PasteFile.get_by_symlink(symlink)

    return redirect(paste_file.url_p)

app/__init__.py: flask启动时,初始化mongodb,注册蓝图

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# File: ik_agent.py
import sys
from flask import Flask, jsonify
# from flask_jwt import JWT
from config import config
import multiprocessing as mp
from app.ik_global import ik_global, vpp_sig_register
from werkzeug.contrib.cache import SimpleCache
# from app.vpp.vpp import Pttool
from app.comm import ik_comm
from app.comm.agent_process import AgentProcess
from app.log import log
from app.ik_global.ik_global import MP_LIST
# from app.vpp.vpp import Pttool
from app.utils.threads import DaemonThreadTimer
from app.comm.ik_thread_work import monitor_vpp_instance_status
from app.utils.ik_util import show_memory_info
from app.utils.auth import authenticate, identity
from app.utils.threads import set_interval
from app.ikdb.exts import db
from flask_jwt import JWT
from werkzeug.contrib.profiler import ProfilerMiddleware
from werkzeug.wsgi import DispatcherMiddleware
from collections import OrderedDict
# from app.views import json_page

def creat_child_processes():
    # 这个函数用于创建并启动agent的子进程,
    # 子进程处理一些不需要运行在主进程的任务,
    # 以提升主进程对 web 请求的响应性能。
    # miscellaneous_works_init()

    # 子进程退出流程,详见函数 kill_all_child
    # 1 主进程捕获 gunicorn 的退出信号;
    # 2 在主进程信号处理函数中,向各个子进程发送 TERM 信号;
    # 3 子进程收到 TERM 信号后,进程自动退出
    # agent_process.start()
    # p = mp.Process(target=vpp_sig_register, name="recv_vpp_signal_process")
    p = AgentProcess(target=vpp_sig_register, name="recv_vpp_signal_process")
    p.start()

    MP_LIST.append(p)


'''
def check_vpp():
    
    if vpp:
        vpp = ik_comm.connect_vpp()
        ik_global.VPP_INSTANCE = vpp
        # ik_global.Logger.info(ik_global.VPP_INSTANCE)
        ik_comm.trigger_config_restore()
        return True
    return False
'''


def create_app(config_name):

    app = Flask(__name__)
    app.config.from_object(config[config_name])
    app.config.setdefault('JWT_SECRET_KEY', 'secret')
    app.debug = True
    # db init 
    # 方式一
    db.init_app(app=app)# 初始化连接数据库
    # 方式二
    from app.ikdb.exts import connect_db
    # init log
    # log.init_log(app)
    ik_global.Logger = log.create_logger()

    # mongodb init
    from app.ikdb.model import models_mongo
    
    # blueprint regester
    from app.views import ik_user_view
    from app.views import ik_agent_view
    from app.views import ik_vpp_view
    from app.views import ik_file_view
    app.register_blueprint(ik_user_view.bp)
    app.register_blueprint(ik_agent_view.bp)
    app.register_blueprint(ik_vpp_view.bp)
    app.register_blueprint(ik_file_view.bp)

    # ik_global.ik_agent_sig_register()
    # app.register_blueprint(ik_auth_view)

    # open profile
    # app.wsgi_app = ProfilerMiddleware(app.wsgi_app, profile_dir="/tmp")

    # 自动封装请求路由为/j/开头的地址为jsonify格式
    app.wsgi_app = DispatcherMiddleware(app.wsgi_app, OrderedDict((('/j', views.json_page),)))

    ik_global.Logger.info("性能测试工具节点--agent启动成功!")
    ik_global.Logger.info("版本号: {}".format(ik_global.__version__))
    ik_global.Logger.info("agent: {} port: {}".format(config[config_name].LISTEN_ADDR, config[config_name].VPP_AGENT_LISTEN_PORT))
    # ik_global.Logger.info("controller_url: {}{}".format(
    #     config[config_name].CONTROLLER_HOST, config[config_name].CONTROLLER_HOST_PATH))
    # ik_global.Logger.info(
    #     "VPP_CORE_DIR: {}".format(config[config_name].VPP_CORE_DIR))
    # ik_global.Logger.info(
    #     "VPP_PLUGINS_DIR: {}".format(config[config_name].VPP_PLUGINS_DIR))
    ik_global.Logger.info(show_memory_info("after vpp started"))
    return app

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值