標籤:錯誤 entity nts util pack device 曝光 typeof package
在與後端的WebSocket通訊時,前端要帶一個proto檔案是一個累贅的事情。首先是明顯的曝光了協議實體物件,再一個瀏覽器用戶端很容易會緩衝該檔案,新的協議更新可能導致用戶端不能使用,另外在cdn伺服器上還需要配置.proto類型用戶端才能下載過去。真是遺毒不淺,自己使用的時候會注意這些,但給別人使用的時候就很不樂觀了,所以這次全部將proto檔案轉成JavaScript對象,省去協議檔案和載入的步驟。
先看代碼:
function createProto(name) { var args = [].slice.call(arguments, 1); var obj = new protobuf.Type(name); for (var i = 0; i < args.length; i++) { var p = args[i]; var key = i + 1; obj.add(new protobuf.Field(p[0], key, p[1] || "string")); } return obj; } function createEnum(name,list) { var obj = new protobuf.Enum(name); for (var i = 0; i < list.length; i++) { obj.add(list[i],i); } return obj; } function loadProto(callback) { if (typeof protobuf == "undefined") return;//說明瀏覽器載入失敗 root = new protobuf.Root().define("IMEntity"); root.add(createProto("Token", ["UserID"], ["Token"], ["Device"], ["Version", "int32"], ["Appkey"])); root.add(createProto("Feedback", ["ResultCode", "int32"], ["ResultData"], ["Seq", "int32"], ["MsgID"])); root.add(createEnum("ReceiptType", ["Receive", "Read"]));
//...
util.triggerCallback(callback); };
proto 主要有兩種類型,Type和Enum。Type對應協議中的message,相當於是類。Enum就是枚舉類型
var Root = protobuf.Root, Type = protobuf.Type, Field = protobuf.Field;var AwesomeMessage = new Type("AwesomeMessage").add(new Field("awesomeField", 1, "string"));var root = new Root().define("awesomepackage").add(AwesomeMessage);
枚舉的建立不要需要Field。只需要add 欄位名即可。那麼接下來的問題是,手寫root.add 也很煩,因為要一個一個對照屬性,不斷的複製粘貼,很容易出錯。所以又做了個自動產生代碼的頁面:
<textarea id="content"> //登陸Token message Token{ string UserID = 1; //登陸介面返回的IMUserID string Token = 2; //登陸介面返回的Token string Device = 3; //用戶端裝置號 int32 Version = 4; //版本號碼,發布前與服務端約定值 string Appkey = 5; //用戶端Appkey } //收到私信 message ReceivePrivateMessage{ string MsgID = 1; //訊息id string SenderID = 2; //寄件者id string ReceiverID = 3; //接收者id string Content = 4; //訊息內容。用戶端轉換成業務相關的實體後,再做後續處理(用戶端使用,伺服器不做任何處理,原樣下發) bool Ack = 5; //是否需要已讀回執 int32 SendDateTime = 6; //訊息發送時間 int32 ContentType = 7; //內容類型(用戶端使用,伺服器不做任何處理,原樣下發) } //回執類型 enum ReceiptType{ Receive = 0; //已回收執(收到訊息後立即發送給伺服器的回執) Read = 1; //已讀回執(使用者進入訊息閱讀介面後發送給伺服器的回執) } </textarea> <div id="result"></div> <script> function start() { $("#result").html(""); $("#result").append(‘root = new protobuf.Root().define("IMProtoEntity")<br>‘); var reg = /("([^\\\"]*(\\.)?)*")|(‘([^\\\‘]*(\\.)?)*‘)|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g,// 過濾注釋 str = $(‘#content‘).val(); // 欲處理的文本 // console.log(str.match(reg));// 列印出:匹配子串 var news = str.replace(reg, ""); // console.log(news); // 列印出:原文本 var reg1 = /[message|enum].*?{/mg; var regobj = /{[^}{]*?}/g;//新地址 var names = news.match(reg1); var protos = news.match(regobj); // console.log(names, protos); var root = {}; for (var i = 0; i < names.length; i++) { var rawname = names[i]; var rawObj = protos[i]; //if (~rawname.indexOf("message")) if (!rawObj) continue; var name = rawname.replace("{", ‘‘).replace("message ", ‘‘).replace("enum ", ‘‘); var obj = { name: name }; if (~rawname.indexOf("enum")) { obj["type"] = "enum"; } rawObj = rawObj.replace("{", ‘‘).replace("}", ‘‘); var protolist = rawObj.split(‘;‘); // console.log("protolist", protolist); var plist = []; for (var j = 0; j < protolist.length; j++) { var p = $.trim(protolist[j]); if (p) { var args = []; var list = p.split(‘ ‘); // console.log("list", list); list.forEach(function (n) { n && args.push(n); }), // console.log("args", args); plist.push(args); } } obj.list = plist; console.log(obj); toProto(obj); } } start(); function toProto(obj) { var root = "root"; var fun = "createProto"; var enumfun = "createEnum"; var str = root + ‘.add(‘; var args; if (!obj.type) {//message args = ‘‘; for (var i = 0; i < obj.list.length; i++) { var item = obj.list[i]; //老協議2.0 if (item[0] == "required" || item[0] == "optional") { item.shift(); } //新協議3.0 if (item[0] != "string") { args += ‘["‘ + item[1] + ‘","‘ + item[0] + ‘"]‘; } else { args += ‘["‘ + item[1] + ‘"]‘; } if (i < obj.list.length - 1) args += ","; } } else {//enum args = ‘[‘; for (var i = 0; i < obj.list.length; i++) { var item = obj.list[i]; args += ‘"‘ + item[0] + ‘"‘; if (i < obj.list.length - 1) args += ","; } args += ‘]‘; } var all = str + (obj.type ? enumfun : fun) + ‘("‘ + obj.name + ‘",‘ + args + ‘));‘; // console.log(all); $("#result").append(all + "<br>"); } </script>
然後頁面上會得到:
紅色部分複製到工程裡面就可以用了。當然要帶上createProto和createEnum兩個方法。proto的格式要規範,畢竟start裡面是以空格split的。相對於protobuf.load("xx.proto",callback)的方式要好很多。load對位置要求比較死板,一定要在根目錄。而且有類型不存在就會報錯,終止程式。add方法不存在找不到類型的錯誤。另外速度也快了很多。
自動產生proto Js語句