首创:gRPC从接口全自动生成所有代码,包括proto,C++ Client,JAVA Server等(不含protobuf本身生成部分) 远程函数调用

Google gRPC实现了一部分代码成生成,还是不够自动化。

我想要的是从现有C++接口,所有代码全自动生成,包括proto,C++ Client,JAVA Server等(不含protobuf本身生成代码部分)。

用法:

1.你已有C++接口,比如pos.h头文件。

2.使用本代码生成pos.proto、pos.cc、pos.java等,主要是调用与对接部分

3.使用gRPC官方插件或命令生成代码,主要是传输、数据序列化与反序列化部分

4.把2份生成的代码,加入你实际项目。

5.运行调试。

实现方案:

 1、已有C++接口,pos.h头文件,比如

DWORD GetVersion(OUT char *pbVersion, IN OUT DWORD *pdwVersionLen, IN BYTE bFlag);
DWORD GetDeviceInfo(OUT BYTE *pbInfo, IN OUT DWORD *pdwInfoLen, IN BYTE bFlag);
DWORD UpdatePosFile(IN BYTE bFileType, IN char *szFilePath, IN DWORD dwFlag);

2、 需要生成代码proto,C++ Client,JAVA Server等(不含protobuf本身生成部分)

准备用java来写生成代码程序。

1)先按行读文件pos.h

2)一个字段一个字段的解析,生成各类代码。

  • IN参数名及类型
  • 函数名
  • 函数返回值类型,OUT参数名及类型
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AutoGenerategRPC {
    public static final String FILENAME="pos.h"; //原始接口头文件

    public static final String PACKAGE="pos"; //要生成的proto中package
    public static final String SERVICE="SdkInterface"; //要生成的proto中service
    public static final String RETURNVALUE="returnValue"; //要生成的proto中函数返回值,void即为空

    public static void main(String[] args) {
        //test();
        generateFileProto();
        generateFileCPPClient();
        generateFileJavaServer();
    }

    private static void generateFileJavaServer() {
        String methods="";
        ArrayList<Method> mList=getMethods(FILENAME);
        for(Method m:mList) {
            String tempRequest="";
            for (Para p : m.inList) {
                tempRequest+="                System.out.println(req.get"+p.name+"());\n"; //对接java接口
            }
            String tempReply="";
            for (Para p : m.outList) {
                tempReply+=".set"+p.name+"(\"HELLO\")"; //对接java接口
            }

            methods +=
            "            @Override\n" +
            "            public void " + m.methodName + "(" + m.methodName + "Request req, StreamObserver<" + m.methodName + "Reply> responseObserver) {\n" +
            tempRequest+
            "                "+ m.methodName +"Reply reply = "+ m.methodName +"Reply.newBuilder()"+tempReply+".build();\n"+
            "                responseObserver.onNext(reply);\n" +
            "                responseObserver.onCompleted();\n" +
            "            }\n" ;
        }



        String contents=
        "        static class "+SERVICE+"Impl extends "+SERVICE+"Grpc."+SERVICE+"ImplBase {\n" +
        methods+
        "        }\n";

        writeToFile(PACKAGE+".java",contents,false); //写入文件
    }

    private static void generateFileCPPClient() {
        String using="";
        String methods="";
        ArrayList<Method> mList=getMethods(FILENAME);
        for(Method m:mList) {
            using += "using " + PACKAGE + "::" + m.methodName + "Request;\n" +
                    "using " + PACKAGE + "::" + m.methodName + "Reply;\n";


            String tempRequest="";
            for (Para p : m.inList) {
                tempRequest+="      request.set_"+p.name.toLowerCase()+"("+p.name+");\n"  ;
            }
            String tempReply="";
            for (Para p : m.outList) {
                tempReply+="          std::cout << \""+p.name+"=\" << reply."+p.name.toLowerCase()+"() << std::endl;\n";
            }

            methods += "  "+m.methodLine.replace(";", "") + "{\n" +
            "      // Data we are sending to the server.\n" +
            "      "+m.methodName+"Request request;\n" +

                    tempRequest+

            "      // Container for the data we expect from the server.\n" +
            "      "+m.methodName+"Reply reply;\n" + "\n" +
            "      // Context for the client. It could be used to convey extra information to\n" +
            "      // the server and/or tweak certain RPC behaviors.\n" +
            "      ClientContext context;\n" + "\n" +
            "      // The actual RPC.\n" +
            "      Status status = stub_->"+m.methodName+"(&context, request, &reply);\n" + "\n" +
            "      // Act upon its status.\n" +
            "      if (status.ok()) {\n" +
            "          std::cout << \"returnValue=\" << reply."+RETURNVALUE.toLowerCase()+"() << std::endl;\n" +

                    tempReply+

            "          return reply."+RETURNVALUE.toLowerCase()+"();\n" +
            "      }\n" +
            "      else {\n" +
            "          std::cout << status.error_code() << \": \" << status.error_message() << std::endl;\n" +
            "          return RPC_FAILED;\n" +
            "      }\n" +
            "  }\n\n";
        }

        String contents="using grpc::Channel;\n" +
                "using grpc::ClientContext;\n" +
                "using grpc::Status;\n" +
                "using "+PACKAGE+"::"+SERVICE+";\n"+
                using+"\n\n"+
                "class "+SERVICE+"Client {\n" +
                " public:\n" +
                "  "+SERVICE+"Client(std::shared_ptr<Channel> channel) : stub_("+SERVICE+"::NewStub(channel)) {}\n"+
                methods+"\n"+
                " private:\n" +
                "  std::unique_ptr<Greeter::Stub> stub_;\n" +
                "};\n";                ;
        writeToFile(PACKAGE+".cc",contents,false); //写入文件
    }

    public static void generateFileProto()
    {
        String method="";
        String para="";

        ArrayList<Method> mList=getMethods(FILENAME);
        for(Method m:mList)
        {
            method+="  rpc "+m.methodName+" ("+m.methodName+"Request) returns ("+m.methodName+"Reply) {}\n";

            String tempRequest="";
            int index=1;
            for (Para p : m.inList) {
                tempRequest+="  "+typeTranslate(ParaType.PROTO,p.type) + " " + p.name+" = "+index+";\n";
                index++;
            }
            String tempReply="";
            index=2; //返回值占了1
            for (Para p : m.outList) {
                tempReply+="  "+typeTranslate(ParaType.PROTO,p.type) + " " + p.name+" = "+index+";\n";
                index++;
            }
            para+="message "+m.methodName+"Request {\n" +
                   tempRequest +
                    "}\n";
            para+="message "+m.methodName+"Reply {\n" +
                    "  "+typeTranslate(ParaType.PROTO,m.returnType)+" "+RETURNVALUE+" = 1;\n" +
                    tempReply +
                    "}\n";
        }


        String contents="syntax = \"proto3\";\n" +
                " \n" +
                "option java_multiple_files = true;\n" +
                "option java_package = \"io.grpc.auto."+PACKAGE.toLowerCase()+"\";\n" +
                "option java_outer_classname = \""+SERVICE+"Proto\";\n" +
                "option objc_class_prefix = \""+PACKAGE.toUpperCase()+"\";\n" +
                "package "+PACKAGE+";\n" +
                " \n" +
                "service  "+SERVICE+"{"
                +method +
                "}\n"+ para;
        writeToFile(PACKAGE+".proto",contents,false); //写入文件
    }


    enum ParaType{PROTO, CPP, JAVA,  }
    public static String typeTranslate(ParaType t, String type)
    {
        if(t==ParaType.PROTO)
        {
            return Constant.TYPE_PROTO.get(type);
        }
        else if(t==ParaType.CPP)
        {

        }
        else  if(t==ParaType.JAVA)
        {
            return Constant.TYPE_JAVA.get(type);
        }
        else
        {

        }
        return "";
    }

    static class Constant {
        public static final Map<String, String> TYPE_PROTO = new HashMap<>();
        static {
            TYPE_PROTO.put("byte", "int32"); //c++,proto
            TYPE_PROTO.put("BYTE", "int32");
            TYPE_PROTO.put("WORD", "int32");
            TYPE_PROTO.put("short", "int32");
            TYPE_PROTO.put("int", "int32");
            TYPE_PROTO.put("DWORD", "int32");
            TYPE_PROTO.put("BYTE*", "bytes");
            TYPE_PROTO.put("BYTE[]", "bytes");
            TYPE_PROTO.put("byte[]", "bytes");
            TYPE_PROTO.put("char*", "bytes");
            TYPE_PROTO.put("WORD*", "bytes");
            TYPE_PROTO.put("DWORD*", "bytes");
        }

        public static final Map<String, String> TYPE_JAVA = new HashMap<>();
        static {
            TYPE_JAVA.put("byte", "int"); //c++,JAVA
            TYPE_JAVA.put("BYTE", "int");
            TYPE_JAVA.put("WORD", "int");
            TYPE_JAVA.put("short", "int");
            TYPE_JAVA.put("int", "int");
            TYPE_JAVA.put("DWORD", "int");
            TYPE_JAVA.put("BYTE*", "byte[]");
            TYPE_JAVA.put("BYTE[]", "byte[]");
            TYPE_JAVA.put("byte[]", "byte[]");
            TYPE_JAVA.put("char*", "byte[]");
            TYPE_JAVA.put("WORD*", "byte[]");
            TYPE_JAVA.put("DWORD*", "byte[]");
        }
    }
    public static void test()
    {
        ArrayList<Method> mList=getMethods("pos.h");
        for(Method m:mList)
        {
            System.out.println(m.returnType +" "+m.methodName);
            for (Para p : m.inList) {
                System.out.println(p.type + " " + p.name);
            }
            for (Para p : m.outList) {
                System.out.println(p.type + " " + p.name);
            }
        }
    }
    enum InOut{
        IN,
        OUT,
        INOUT,
    }
    static class Para{
        InOut inOut;
        String type; //参数类型
        String name; //参数名
    }
    static class Method{
        String methodLine;
        String methodName; //函数名
        String returnType; //返回类型
        ArrayList<Para> inList =new ArrayList<>();
        ArrayList<Para> outList =new ArrayList<>();
    }
    public static ArrayList<Method> getMethods(String fileName)
    {
        ArrayList<Method> mList=new ArrayList<>();
        ArrayList<String> arrayList =readFile(fileName);
        for(String line:arrayList)
        {
            mList.add(getMethod(line));
        }
        return mList;
    }

    public static Method getMethod(String line)
    {
        Method method=new Method();
        method.methodLine=line;
        method.methodName= getRegEx(line,"(?<=\\s).*?(?=\\()").trim();
        method.returnType=getRegEx(line,".*?(?=\\s)").trim(); //返回值 函数名前
        String paraStr=getRegEx(line,"(?<=\\().*?(?=\\))").trim(); //()中内容
        String[] paras=paraStr.split(","); //按,分割成单个参数
        if(paras.length==0) //无参数
        {

        }
        else { //有参数
            for (String para : paras) {
                //System.out.println(para.trim());
                if (para.trim().equals("void")) //无参数
                {

                } else {    //有参数
                    String[] part = para.split(" "); //按空格分割 单个参数 IN OUT BYTE bKeyType
                    if(part.length>2) {
                        if (para.contains("*") ) //指针类型
                        {
                            part[part.length - 2] = part[part.length - 2].replace("*", "")+"*"; //类型 指针合并到类型中
                            part[part.length - 1] = part[part.length - 1].replace("*", ""); //参数名
                        }
                        if(para.contains("[") ) //也是指针类型,可能有[]、[2]
                        {
                            part[part.length - 2] = part[part.length - 2].replaceAll("\\[[0-9]*?\\]", "")+"*"; //类型 指针合并到类型中
                            part[part.length - 1] = part[part.length - 1].replaceAll("\\[[0-9]*?\\]", ""); //参数名
                        }
                        Para p=new Para();
                        p.type=part[part.length - 2]; //类型
                        p.name=part[part.length - 1]; //参数名
                        if(para.contains("IN"))
                        {
                            method.inList.add(p);
                        }
                        if(para.contains("OUT"))
                        {
                            method.outList.add(p);
                        }
                    }
                }
            }
        }
        return method;
    }
    /**
     * 功能:
     * @param str 要匹配的字符串
     * @param reg 正则表达式
     * @return 返回“”或1条匹配结果
     */
    public static String getRegEx(String str,String reg)  //返回0或1条匹配结果
    {
        String result="";
        // 创建 Matcher 对象
        Matcher m = Pattern.compile(reg, Pattern.COMMENTS).matcher(str);
        if( m.find() )
        {
            result = m.group();
        }
        return result;
    }

    public static void writeToFile(String pathName,String contents,boolean append)
    {
        try{
            File file =new File(pathName);
            if(!file.exists()){ //if file doesnt exists, then create it
                file.createNewFile();
            }
            FileWriter fileWritter = new FileWriter(file.getName(),append);//true = append file
            fileWritter.write(contents);
            fileWritter.close();
            System.out.println("write Done");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    public static String manualReplaceSpecial(String line)
    {
        line=line.replace("IN TRANSACTION_OPTIONS *pstTransactionOptions","IN BYTE bPINEncKeyType,IN BYTE pbPINEncKeyIndex[2],IN BYTE bWorkingKeyAlg,IN BYTE bPINBlockFormat,IN BYTE bMagTransServiceCodeProcess,IN BYTE pbPINPolicy[2],IN BYTE pbPINLen[2],IN BYTE bMAGTransOnlinePIN");
        return line;
    }
    public static ArrayList<String> readFile(String name) {
        // 使用ArrayList来存储每行读取到的字符串
        ArrayList<String> arrayList = new ArrayList<>();
        try {
            FileReader fr = new FileReader(name);
            BufferedReader bf = new BufferedReader(fr);
            String line;
            // 按行读取字符串
            while ((line = bf.readLine()) != null) {
                line=line.trim(); //去掉首尾空格
                while(line.contains("  ")) { //去掉所有多余空格
                    line = line.replace("  ", " "); //多个空格全合并成一个
                }
                if(!line.equals("") && !line.startsWith("//")) { //去掉空行和注释行
                    line=manualReplaceSpecial(line);//手工替换特殊内容 结构体等
                    arrayList.add(line);
                    //System.out.println(line);
                }
            }
            bf.close();
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return arrayList;
    }
}

示例pos.h

DWORD LoadDukptIpek(IN WORD wKeyIndex, IN BYTE bAlg, IN BYTE bProtectKeyType, IN WORD wProtectKeyIndex, IN BYTE *pbKeyData, IN WORD wKeyDataLen,	IN BYTE *pbKSN, IN BYTE bKSNLen, IN OUT BYTE *pbKCV, IN BYTE bKCVLen, IN BYTE bKCVMode);
DWORD LoadSymKey(IN BYTE bKeyType , IN WORD wKeyIndex, IN BYTE bAlg, IN BYTE bProtectKeyType, IN WORD wProtectKeyIndex, IN BYTE *pbKeyData, IN WORD wKeyDataLen, IN OUT BYTE *pbKCV, IN BYTE bKCVLen, IN BYTE bKCVMode)
DWORD GetKSN(IN WORD wKeyIndex, OUT BYTE *pbKSN, IN OUT BYTE *pbKSNLen);

生成pos.proto、pos.java、pos.cc等。如下图: 

相关常见定义

typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned char *PUCHAR;
typedef unsigned short USHORT;

typedef const void *LPCVOID;

typedef unsigned long *PDWORD;
typedef long LONG;
typedef const char *LPCSTR;
typedef const BYTE *LPCBYTE;
typedef BYTE *LPBYTE;
typedef DWORD *LPDWORD;
typedef char *LPSTR;


typedef unsigned short WORD;
typedef unsigned long *PULONG;
#ifndef IN
#define IN
#endif

#ifndef OUT
#define OUT
#endif

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄人软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值