import yaml from 'js-yaml' ; import { find , isEmpty , map , omit , pull } from 'lodash/fp' ; import { ApiRecord , API_DATA_TYPE , BPMsg , SimpleReq , SOCKET_MSG_TAG_API } from '../../lib/interface' ; import ss from '../socket-server' ; import { replaceRecord } from './api-manager' ; import configManager from './config-manager' ; import { parseSnippetContent } from './snippet-manager' ; const BPS = { } ; class BPMsgQueue { private queue : BPMsg [ ] = [ ] ; enabled = true ; push < T > ( record ) { if ( ! this . enabled ) { return Promise . resolve ( < T > < unknown > ( record . resp || record . req ) ) ; } return new Promise ( ( resolve , reject ) => { const { uuid , req , resp , parsedUrl } = record ; const msg = { uuid , method : req . method , parsedUrl , type : resp ? API_DATA_TYPE . RESPONSE : API_DATA_TYPE . REQUEST , httpDetail : resp || req , resolve , reject } ; this . queue . push ( msg ) ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_MSG_NEW , omit ( 'httpDetail' , msg ) ) ; } ) ; } getQueueMsgs ( ) { return map ( omit ( [ 'httpDetail' , 'resolve' ] ) ) ( this . queue ) ; } getMsg ( uuid ) { return find ( { uuid } , this . queue ) ; } passBPMsg ( uuid , httpDetail ? ) { const msg = this . getMsg ( uuid ) ; if ( ! msg ) return ; msg . resolve ( httpDetail || msg . httpDetail ) ; this . queue = pull ( msg , this . queue ) ; } passAll ( ) { this . queue . forEach ( ( msg ) => { msg . resolve ( msg . httpDetail ) ; } ) ; this . queue = [ ] ; } abortMSg ( uuid ) { const msg = < BPMsg > find ( { uuid } , this . queue ) ; if ( ! msg ) return ; msg . reject ( new Error ( '请求被中断：' + msg . parsedUrl . shortHref ) ) ; } } ; const bpMsgQueue = new BPMsgQueue ( ) ; configManager . on ( 'afterConfigInit' , ( ) => { Object . assign ( BPS , { ... ( configManager . get ( configManager . key . BREAKPOINT ) || { } ) } ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_GET , ( cb ) => { cb ( BPS ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_UPDATE_BY_URL , ( key , enableTypes ) => { if ( isEmpty ( enableTypes ) ) { delete BPS [ key ] ; } else { BPS [ key ] = enableTypes ; } configManager . emit ( 'update' , configManager . key . BREAKPOINT , BPS ) ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_UPDATE , BPS ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_GET_QUEUE , ( cb ) => { cb ( bpMsgQueue . getQueueMsgs ( ) ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_START , ( uuid , cb ) => { cb ( bpMsgQueue . getMsg ( uuid ) ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_ABORT , ( uuid ) => { bpMsgQueue . abortMSg ( uuid ) ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_MSG_REMOVE , uuid ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_DONE , ( { id , code } ) => { bpMsgQueue . passBPMsg ( id , code && yaml . load ( code ) ) ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_MSG_REMOVE , id ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_PASS_ALL , ( ) => { bpMsgQueue . passAll ( ) ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_MSG_REMOVE , 'all' ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_ENABLED , ( cb ) => { cb ( bpMsgQueue . enabled ) ; } ) ; ss . on ( SOCKET_MSG_TAG_API . BP_MSG_SET_ENABLED , ( val ) => { bpMsgQueue . enabled = val ; ss . broadcast ( SOCKET_MSG_TAG_API . BP_MSG_SET_ENABLED , val ) ; } ) ; export async function throughBP4Req ( record ) { const { parsedUrl } = record ; let rsRecord = record ; if ( ( BPS [ parsedUrl . shortHref ] || [ ] ) . includes ( API_DATA_TYPE . REQUEST ) ) { try { const mHttpDetail = await bpMsgQueue . push < SimpleReq > ( record ) ; rsRecord = await { ... record , req : mHttpDetail } ; replaceRecord ( rsRecord ) ; } catch ( err ) { rsRecord . resp = { statusCode : 500 , headers : { } , body : err . message } ; replaceRecord ( rsRecord ) ; throw err ; } return rsRecord ; } return record ; } export async function throughBP4Resp ( record ) { const { resp , parsedUrl } = record ; let rsRecord = record ; if ( ( BPS [ parsedUrl . shortHref ] || [ ] ) . includes ( API_DATA_TYPE . RESPONSE ) ) { try { const mHttpDetail = await bpMsgQueue . push < SimpleReq > ( record ) ; rsRecord = Object . assign ( { } , record , { resp : parseSnippetContent ( mHttpDetail ) ( resp ) } ) ; replaceRecord ( rsRecord ) ; } catch ( err ) { rsRecord . resp . body = err . message ; replaceRecord ( rsRecord ) ; throw err ; } return rsRecord ; } return record ; }