const protobuf = require('protobufjs'); const parseArgs = require('minimist'); const fs = require('fs'); const assert = require('assert'); class PBTools { constructor() { this.csMsgIdPb = null; this.csProtoPb = null; this.ssMsgIdPb = null; this.ssProtoPb = null; this.mtPb = null; this.protoDir = './proto/'; } async init() { { this.csProtoPb = await (new protobuf.Root()).load( this.protoDir + 'cs_proto.proto', { 'keepCase': true } ); } { this.csMsgIdPb = await (new protobuf.Root()).load( this.protoDir + 'cs_msgid.proto', { 'keepCase': true } ); this.csCmMsgId = this.csMsgIdPb.lookup('CMMessageId_e'); this.csSmMsgId = this.csMsgIdPb.lookup('SMMessageId_e'); } /* { this.ssProtoPb = await (new protobuf.Root()).load( this.protoDir + 'ss_proto.proto', { 'keepCase': true } ); } { this.ssMsgIdPb = await (new protobuf.Root()).load( this.protoDir + 'ss_msgid.proto', { 'keepCase': true } ); this.ssSSmMsgId = this.ssMsgIdPb.lookup('SSMMessageId_e'); }*/ { this.mtPb = await (new protobuf.Root()).load( this.protoDir + 'mt.proto', { 'keepCase': true } ); } await this.genCsAutoGen(); await this.genMtbAutoGen(); //await this.genSsAutoGen(); } async genCsAutoGen() { let data = `use std::rc::{Rc, Weak}; use std::cell::RefCell; use crate::cs::cs_proto as cs; use crate::cs::cs_msgid as cs_msgid; pub struct Handler { msg_id: i32, handler_id: i32, cb: Box::, } static mut HANDLERS: Vec> = Vec::new(); pub fn get_net_msg_handler(msg_id: u16) -> &'static Option { unsafe { if (msg_id as usize) < HANDLERS.len() { return &HANDLERS[msg_id as usize]; } else { return &None; } } } pub fn reg_handler_id(msg_id: u16, handler_id: i32){ unsafe { if (msg_id as usize) < HANDLERS.len() { match &mut HANDLERS[msg_id as usize] { Some(v) => { v.handler_id = handler_id; } None => { } } } } } /* func DispatchMsg(handler *CsNetMsgHandler, hdr *f5.MsgHdr, msgHandler MsgHandler) { handler.Cb(hdr, msgHandler) } func ParsePb(msgId uint16, data []byte) interface{} { handler := handlers[msgId] if handler == nil { return nil } return handler.ParseCb(data) }*/ `; data += ` pub trait MsgHandler {`; this.csProtoPb.nested.cs.nestedArray.forEach( (item) => { if (item.name[0] == 'C' && item.name[1] == 'M') { const finalyName = this.converLowCaseName(item.name); data += ` fn ${finalyName}(&self, _: &f9::MsgHdr, _: Rc::>) { panic!("not implement"); } `; } }); data += ` } `; data += ` pub fn registe_handlers() { unsafe { HANDLERS.reserve(2000); for i in 0..1999 { HANDLERS.push(None); } `; this.csProtoPb.nested.cs.nestedArray.forEach( (item) => { if (item.name[0] == 'C' && item.name[1] == 'M') { data += ` HANDLERS[cs_msgid::CMMessageId_e::_${item.name} as usize] = Some( Handler { msg_id: cs_msgid::CMMessageId_e::_${item.name} as i32, handler_id: 0, cb: Box::new(|_: &f9::MsgHdr, _: &dyn MsgHandler| { }), }); `; } }); data += ` } }`; fs.writeFileSync('./src/cs/cs_auto_gen.rs', data); } async genSsAutoGen() { let data = `package ss import ( "f5" proto "github.com/golang/protobuf/proto" ) type SsNetMsgHandler f5.NetMsgHandler[MsgHandler]; type MsgHandlerImpl struct { } var handlers [2000]*SsNetMsgHandler func GetNetMsgHandler(msgId uint16) *SsNetMsgHandler { handler := handlers[msgId] return handler } func DispatchMsg(handler *SsNetMsgHandler, hdr *f5.MsgHdr, msgHandler MsgHandler) { handler.Cb(hdr, msgHandler) } func RegHandlerId(msgId int, handlerId int) { handler := handlers[msgId] handler.HandlerId = handlerId } func ParsePb(msgId uint16, data []byte) interface{} { handler := handlers[msgId] if handler == nil { return nil } return handler.ParseCb(data) } `; data += ` type MsgHandler interface {`; this.ssProtoPb.nested.ss.nestedArray.forEach( (item) => { if (item.name[0] == 'S' && item.name[1] == 'S') { data += ` ${item.name}(*f5.MsgHdr, *${item.name})`; } }); data += ` } `; this.ssProtoPb.nested.ss.nestedArray.forEach( (item) => { if (item.name[0] == 'S' && item.name[1] == 'S') { data += ` func (this *MsgHandlerImpl) ${item.name}(hdr *f5.MsgHdr, msg *${item.name}) { } `; } }); this.ssProtoPb.nested.ss.nestedArray.forEach( (item) => { if (item.name[0] == 'S' && item.name[1] == 'S') { data += ` func (this *${item.name}) GetNetMsgId() uint16 { return uint16(SSMessageIdE__${item.name}) } `; } else if (item.name[0] == 'S' && item.name[1] == 'M') { data += ` func (this *${item.name}) GetNetMsgId() uint16 { return uint16(SMMessageIdE__${item.name}) } `; } }); data += ` func init() { `; this.ssProtoPb.nested.ss.nestedArray.forEach( (item) => { if (item.name[0] == 'S' && item.name[1] == 'S') { data += ` handlers[int(SSMessageIdE__${item.name})] = &SsNetMsgHandler{ MsgId: int(SSMessageIdE__${item.name}), ParseCb: func (data []byte) interface{} { msg := &${item.name}{} proto.Unmarshal(data, msg) return msg }, Cb: func (hdr *f5.MsgHdr, handler MsgHandler) { handler.${item.name}(hdr, hdr.Msg.(*${item.name})) }, } `; } }); data += ` }`; fs.writeFileSync('./ss/ss.auto_gen.go', data); } async genMtbAutoGen() { let data = `use std::rc::{Rc, Weak}; use std::cell::RefCell; `; this.mtPb.nested.mt.nestedArray.forEach( (item) => { data += `pub struct ${item.name} {\n`; item.fieldsArray.forEach ( (item2, index) => { assert(item2.id <= 127); data += ` ${item2.name}: ` + this.dumpClassField(item, item2, index) + `,\n`; } ); data += `} `; } ); data += ''; /* this.mtPb.nested.mt.nestedArray.forEach( (item) => { item.fieldsArray.forEach ( (item2, index) => { const newName = this.converUpperCamelCaseName(item2.name); data += `func (this *${item.name}) Get${newName}() ` + this.dumpClassField(item, item2, index) + ` {\n`; data += ` return this.${item2.name}\n`; data += `}\n\n`; data += `func (this *${item.name}) Has${newName}() bool {\n`; if (item2.id < 64) { data += ` return (this._flags1_ & (uint64(1) << ${item2.id})) > 0\n`; } else { data += ` return (this._flags2_ & (uint64(1) << (${item2.id} - 64))) > 0\n`; } data += `}\n\n`; } ); } ); this.mtPb.nested.mt.nestedArray.forEach( (item) => { data += ` func (this *${item.name}) LoadFromKv(kv map[string]interface{}) { `; item.fieldsArray.forEach ( (item2, index) => { if (item2.id < 64) { data += ` f5.ReadMetaTableField(&this.${item2.name}, "${item2.name}", &this._flags1_, ${item2.id}, kv)\n`; } else { data += ` f5.ReadMetaTableField(&this.${item2.name}, "${item2.name}", &this._flags2_, ${item2.id} - 64, kv)\n`; } } ); data += '}\n'; } );*/ fs.writeFileSync('./src/mtb/mtb_auto_gen.rs', data); } dumpClassField(cls, field, index) { const fieldName = field.name; switch (field.type) { case 'int32': { return `Option`; } break; case 'int64': { return `Option`; } break; case 'float': { return `Option`; } break; case 'double': { return `Option`; } break; case 'string': { return `Option`; } break; default: console.log(field); assert(false, 'error field type:' + field.type); break; } } converUpperCamelCaseName(name) { let newName = ''; let preIs_ = false; for (let i = 0; i < name.length; ++i) { if (i == 0) { newName += name[i].toUpperCase(); preIs_ = name[i] == '_'; } else { if (preIs_) { if (name[i] != '_') { newName += name[i].toUpperCase(); } } else { if (name[i] != '_') { newName += name[i]; } } preIs_ = name[i] == '_'; } } return newName; } converLowCaseName(name) { let newName = 'cm'; let preIs_ = false; for (let i = 2; i < name.length; ++i) { if (name[i].charCodeAt(0) >= 65 && name[i].charCodeAt(0) <= 90) { newName += '_' + name[i].toLowerCase(); } else { newName += name[i]; } } return newName; } } (new PBTools).init();