⾸创:gRPC从接⼝全⾃动⽣成所有代码,包括
proto,C++Client,JAVASer。。。
Google gRPC实现了⼀部分代码成⽣成,还是不够⾃动化。
我想要的是从现有C++接⼝,所有代码全⾃动⽣成,包括proto,C++ Client,JAVA Server等(不含protobuf本⾝⽣成代码部分)。⽤法:
1.你已有C++接⼝,⽐如pos.h头⽂件。
2.使⽤本代码⽣成pos.proto、、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 Matcher;
import 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() {
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."+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 +"wBuilder()"+tempReply+".build();\n"+
" Next(reply);\n" +
" Completed();\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_"+LowerCase()+"("+p.name+");\n" ;
}
String tempReply="";
for (Para p : m.outList) {
tempReply+=" std::cout << \""+p.name+"=\" << reply."+LowerCase()+"() << std::endl;\n";
}
methods += " "+place(";", "") + "{\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" +
" if (status.ok()) {\n" +
" std::cout << \"returnValue=\" << reply."+LowerCase()+"() << std::endl;\n" +
tempReply+
" return reply."+LowerCase()+"();\n" +
" }\n" +
" else {\n" +
" std::cout << _code() << \": \" << _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.pe) + " " + p.name+" = "+index+";\n";
index++;
}
String tempReply="";
index=2; //返回值占了1
for (Para p : m.outList) {
tempReply+=" "+typeTranslate(ParaType.pe) + " " + p.name+" = "+index+";\n";
index++;
}
para+="message "+m.methodName+"Request {\n" +
tempRequest +
"}\n";
para+="message "+m.methodName+"Reply {\n" +
" "+typeTranslate(ParaType.urnType)+" "+RETURNVALUE+" = 1;\n" +
tempReply +
"}\n";
}
String contents="syntax = \"proto3\";\n" +
" \n" +
"option java_multiple_files = true;\n" +
"option java_package = \"io.grpc.auto."+LowerCase()+"\";\n" +
"option java_outer_classname = \""+SERVICE+"Proto\";\n" +
"option java_outer_classname = \""+SERVICE+"Proto\";\n" +
"option objc_class_prefix = \""+UpperCase()+"\";\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);
}
else if(t==ParaType.CPP)
{
}
else if(t==ParaType.JAVA)
{
return Constant.(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[]");
}
java中split的用法}
}
public static void test()
{
ArrayList<Method> mList=getMethods("pos.h");
for(Method m:mList)
{
System.out.urnType +" "+m.methodName);
for (Para p : m.inList) {
System.out.pe + " " + p.name);
}
for (Para p : m.outList) {
System.out.pe + " " + 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();
String paraStr=getRegEx(line,"(?<=\\().*?(?=\\))").trim(); //()中内容
String[] paras=paraStr.split(","); //按,分割成单个参数
if(paras.length==0) //⽆参数
{
}
else { //有参数
for (String para : paras) {
/
/System.out.im());
if (im().equals("void")) //⽆参数
{
} else { //有参数
String[] part = para.split(" "); //按空格分割单个参数 IN OUT BYTE bKeyType if(part.length>2) {
if (ains("*") ) //指针类型
{
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论