import * as fs from "fs" ; import * as path from "path" ; import { v4 as uuidv4 } from "uuid" ; import * as compressing from "compressing" ; import { Body , Controller , Get , Post , Query , Validation } from "../core" ; import { ComponentDto , ComponentTypeDto } from "../dto" ; import ComponentService from "../service/ComponentService" ; import AppError from "../common/AppError" ; import { tmpdir } from "os" ; import { defaultStaticConfig } from "../config" ; import BaseController from "./BaseController" ; const { ncp } = require ( "ncp" ) ; const rimraf = require ( "rimraf" ) ; function rmdir ( dir ) { return rimraf . sync ( dir ) ; } @ Controller ( "/component" ) export default class ComponentController extends BaseController { constructor ( private readonly service ) { super ( ) ; } private readonly libSavePath = defaultStaticConfig . libPath ; param types param pid formatTypes ( types , pid ? ) { const arr = [ ] ; types . forEach ( ( v ) => { if ( v . pid === pid ) { const children = this . formatTypes ( types , v . id ) ; if ( children . length > 0 ) { v . children = children ; } arr . push ( v ) ; } } ) ; return arr ; } param zipFile param dest param libId unzip ( zipFile , dest , libId ? ) { return new Promise ( ( resolve , reject ) => { fs . mkdtemp ( path . join ( tmpdir ( ) , "compoents-" ) , ( err , directory ) => { if ( err ) reject ( err ) ; compressing . zip . uncompress ( zipFile , directory ) . then ( ( ) => { const decFile = `${ directory }/declare.json` ; fs . open ( decFile , "r" , async ( openErr , fd ) => { if ( openErr ) { rmdir ( directory ) ; reject ( new Error ( `读取declare.json失败:${ openErr . code }` ) ) ; return ; } const descText = fs . readFileSync ( fd , { encoding : "utf8" } ) ; fs . closeSync ( fd ) ; try { const descJson = JSON . parse ( descText ) ; if ( ! descJson . name || ! descJson . version ) { rmdir ( directory ) ; reject ( new Error ( "解释declare.json失败，请写上name和version" ) ) ; return ; } if ( ! libId ) { const rel = await this . service . findByName ( descJson . name , descJson . version ) ; if ( rel ) { reject ( new Error ( `${ descJson . name }已经存在` ) ) ; return ; } } else { const rel = await this . service . findById ( libId ) ; if ( ! rel || rel . name !== descJson . name ) { reject ( new Error ( "上传的组件与原组件不一致" ) ) ; return ; } } const sid = uuidv4 ( ) ; const savePath = `${ dest }/${ sid }` ; this . ncpAndRm ( directory , savePath ) . then ( ( rel ) => { if ( rel ) { resolve ( { ... descJson , sid , } ) ; } else { reject ( new Error ( `${ descJson . name }保存失败` ) ) ; } } ) ; } catch ( e ) { console . log ( e ) ; rmdir ( directory ) ; reject ( new Error ( "解释package.json失败" ) ) ; } } ) ; } ) . catch ( ( ) => { rmdir ( directory ) ; reject ( new Error ( "解压失败" ) ) ; } ) ; } ) ; } ) ; } async ncpAndRm ( fromPath , savePath ) { return new Promise ( ( resolve , reject ) => { if ( ! fs . existsSync ( fromPath ) ) { resolve ( false ) ; return ; } rmdir ( savePath ) ; fs . mkdirSync ( savePath , { recursive : true } ) ; ncp ( fromPath , savePath , ( ncperr ) => { if ( ncperr ) { resolve ( false ) ; return ; } rmdir ( fromPath ) ; resolve ( true ) ; } ) ; } ) ; } /**
     * 组件类型树
     */ @ Get ( "/types" ) async getTypes ( ) { const rel = await this . service . findTypes ( ) ; if ( ! rel ) return this . success ( [ ] ) ; return this . success ( rel ? this . formatTypes ( rel , undefined ) : [ ] ) ; } /**
     * 添加组件类型
     */ @ Post ( "/type/add" ) async addType ( @ Body ( new Validation ( { groups : [ "add" ] } ) ) dto ) { const rel = await this . service . addType ( dto ) ; if ( rel ) { return this . success ( rel ) ; } return this . fail ( "添加失败" ) ; } /**
     * 添加组件类型
     */ @ Post ( "/type/update" ) async updateType ( @ Body ( new Validation ( { groups : [ "update" ] } ) ) dto ) { const rel = await this . service . updateType ( dto ) ; if ( rel ) { return this . success ( rel ) ; } return this . fail ( "更新失败" ) ; } /**
     * 添加组件类型
     */ @ Get ( "/type/delete" ) async delType ( @ Query ( "id" ) id ) { const rel = await this . service . delType ( id ) ; if ( rel ) { return this . success ( null ) ; } return this . fail ( "删除失败" ) ; } /**
     * 组件列表
     */ @ Get ( "/list" ) async list ( @ Query ( ) query ? ) { const rel = await this . service . findAll ( query ? query . type : undefined ) ; return this . success ( rel ) ; } param file @ Post ( "/upload" ) async upload ( ctx ) { const { req } = ctx ; const data = await req . file ( ) ; const fields = data . fields as any ; const rel = await this . unzip ( data . file , this . libSavePath , fields . libId ? fields . libId . value : undefined ) . catch ( ( error ) => { AppError . assert ( error ? error . message : "上传失败" ) ; } ) ; return this . success ( rel ) ; } param dto @ Post ( "/add" ) async addComponent ( @ Body ( new Validation ( { groups : [ "add" ] } ) ) dto ) { const rel = await this . service . add ( { ... dto , origin : 2 } ) ; const dest = this . libSavePath ; const savePath = `${ dest }/${ dto . name }${ dto . version }` ; const directory = `${ dest }/${ dto . sid }` ; if ( ! fs . existsSync ( directory ) ) { return this . fail ( `组件${ dto . name }${ dto . version }不存在` ) ; } if ( rel && ( await this . ncpAndRm ( directory , savePath ) ) ) { return this . success ( rel ) ; } return this . fail ( "添加失败" ) ; } param dto @ Post ( "/update" ) async updateComponent ( @ Body ( new Validation ( { groups : [ "update" ] } ) ) dto ) { const rel = await this . service . update ( { ... dto , origin : 2 } ) ; const dest = this . libSavePath ; const savePath = `${ dest }/${ dto . name }${ dto . version }` ; const directory = `${ dest }/${ dto . sid }` ; let cpRel = true ; if ( dto . sid ) { cpRel = await this . ncpAndRm ( directory , savePath ) ; } if ( rel && cpRel ) { return this . success ( rel ) ; } return this . fail ( "更新失败" ) ; } /**
     * 组件列表
     */ @ Get ( "/delete" ) async del ( @ Query ( "id" ) id ) { const rel = await this . service . delete ( id ) ; if ( rel ) { const savePath = `${ this . libSavePath }/${ rel . name }${ rel . version }` ; rmdir ( savePath ) ; } else { return this . fail ( "删除失败" ) ; } return this . success ( null ) ; } /**
     * 组件详情
     */ @ Get ( "/detail" ) async detail ( @ Query ( "id" ) id ) { const rel = await this . service . findById ( id ) ; return this . success ( rel ) ; } }