aozhiwei b0cd82dd97 1
2024-06-21 12:01:32 +08:00

475 lines
11 KiB
JavaScript

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 loadCsPb() {
if (!fs.existsSync(this.protoDir + 'cs_proto.proto')) {
console.error('cs_proto.proto file not exists');
return;
}
{
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');
}
}
async loadSsPb() {
if (!fs.existsSync(this.protoDir + 'ss_proto.proto')) {
console.error('ss_proto.proto file not exists');
return;
}
{
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');
}
}
async loadMtPb() {
if (!fs.existsSync(this.protoDir + 'mt.proto')) {
console.error('mt.proto file not exists');
return;
}
{
this.mtPb = await (new protobuf.Root()).load(
this.protoDir + 'mt.proto',
{
'keepCase': true
}
);
}
}
async init() {
await this.loadCsPb();
await this.loadSsPb();
await this.loadMtPb();
if (this.csProtoPb) {
await this.genCsAutoGen();
}
if (this.mtPb) {
await this.genMtbAutoGen();
}
if (this.ssProtoPb) {
await this.genSsAutoGen();
}
}
async genCsAutoGen() {
let data = `package cs
import (
"f5"
proto "github.com/golang/protobuf/proto"
)
type CsNetMsgHandler f5.NetMsgHandler[MsgHandler];
type MsgHandlerImpl struct {
}
var handlers [2000]*CsNetMsgHandler
func GetNetMsgHandler(msgId uint16) *CsNetMsgHandler {
handler := handlers[msgId]
return handler
}
func DispatchMsg(handler *CsNetMsgHandler, 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.csProtoPb.nested.cs.nestedArray.forEach(
(item) => {
if (item.name[0] == 'C' &&
item.name[1] == 'M') {
data += `
${item.name}(*f5.MsgHdr, *${item.name})`;
}
});
data += `
}
`;
this.csProtoPb.nested.cs.nestedArray.forEach(
(item) => {
if (item.name[0] == 'C' &&
item.name[1] == 'M') {
data += `
func (this *MsgHandlerImpl) ${item.name}(hdr *f5.MsgHdr, msg *${item.name}) {
}
`;
}
});
this.csProtoPb.nested.cs.nestedArray.forEach(
(item) => {
if (item.name[0] == 'C' &&
item.name[1] == 'M') {
data += `
func (this *${item.name}) GetNetMsgId() uint16 {
return uint16(CMMessageIdE__${item.name})
}
`;
} else if (item.name[0] == 'S' &&
item.name[1] == 'M') {
data += `
func (this *${item.name}) GetNetMsgId() uint16 {
return uint16(SMMessageIdE__${item.name})
}
`;
}
});
this.csProtoPb.nested.cs.nestedArray.forEach(
(item) => {
if (item.name[0] == 'S' &&
item.name[1] == 'M') {
let hasErrCodeField = false;
let hasErrMsgField = false;
item.fieldsArray.forEach(
(item2) => {
if (item2.name == 'errcode') {
hasErrCodeField = true;
} else if (item2.name == 'errmsg') {
hasErrMsgField = true;
}
});
if (hasErrCodeField && hasErrMsgField) {
data += `
func (this *${item.name}) Err(errCode int32, errMsg string) *${item.name} {
this.Errcode = proto.Int32(errCode)
this.Errmsg = proto.String(errMsg)
return this
}
`;
}
}
});
data += `
func init() {
`;
this.csProtoPb.nested.cs.nestedArray.forEach(
(item) => {
if (item.name[0] == 'C' &&
item.name[1] == 'M') {
data += `
handlers[int(CMMessageIdE__${item.name})] = &CsNetMsgHandler{
MsgId: int(CMMessageIdE__${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('./cs/cs.auto_gen.go', 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 = `package mtb
import (
"f5"
)
`;
this.mtPb.nested.mt.nestedArray.forEach(
(item) => {
data += `type ${item.name} struct {\n`;
item.fieldsArray.forEach
(
(item2, index) => {
assert(item2.id <= 127);
const newFieldName = this.keyWordReplace(item2.name);
data += ` ${newFieldName} ` + this.dumpClassField(item, item2, index) + `\n`;
}
);
data += `
_flags1_ uint64
_flags2_ uint64
}
`;
}
);
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`;
const newFieldName = this.keyWordReplace(item2.name);
data += ` return this.${newFieldName}\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) => {
const newFieldName = this.keyWordReplace(item2.name);
if (item2.id < 64) {
data += ` f5.ReadMetaTableField(&this.${newFieldName}, "${item2.name}", &this._flags1_, ${item2.id}, kv)\n`;
} else {
data += ` f5.ReadMetaTableField(&this.${newFieldName}, "${item2.name}", &this._flags2_, ${item2.id} - 64, kv)\n`;
}
}
);
data += '}\n';
}
);
fs.writeFileSync('./mtb/mtb.auto_gen.go', data);
}
dumpClassField(cls, field, index) {
const fieldName = field.name;
switch (field.type) {
case 'int32':
{
return `int32`;
}
break;
case 'int64':
{
return `int64`;
}
break;
case 'float':
{
return `float32`;
}
break;
case 'double':
{
return `float64`;
}
break;
case 'string':
{
return `string`;
}
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;
}
keyWordReplace(name) {
const keyWords = {
"type": 1
};
if (keyWords[name]) {
return name + "_";
} else {
return name;
}
}
}
(new PBTools).init();