栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

首创: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 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 +=
            "            @Overriden" +
            "            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 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 ton" +
            "      // 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" +
            "  }nn";
        }

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

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

        ArrayList 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 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 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 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 inList =new ArrayList<>();
        ArrayList outList =new ArrayList<>();
    }
    public static ArrayList getMethods(String fileName)
    {
        ArrayList mList=new ArrayList<>();
        ArrayList 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;
    }
    
    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 readFile(String name) {
        // 使用ArrayList来存储每行读取到的字符串
        ArrayList 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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/605248.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号