IPromise <ProtoMessage> mergePromise(IEnumerable <ProtoMessage> partialMessages) { var promise = new Promise <ProtoMessage>((resolve, reject) => { var fullMessage = new ProtoMessage(); foreach (var pm in partialMessages) { if (pm != null) { fullMessage.AddProtoObjects(pm); } } resolve(fullMessage); }); return(promise); }
//most complicated logic we have. Need to loop over the routing objects and handle //objects coming in the stream in order //therefore we construct a series of promises public IPromise <ProtoMessage> RouteMessage(ProtoMessage protoMessage) { var allPromises = new List <Promise <ProtoMessage> >(); // we're going to loop over each message sent // and for each handler of those objects // processing each partial response in order // and sending back the full response in the end Debug.Log($"Objects to route: {protoMessage.ProtoObjectList.Count}"); foreach (var msgTuple in protoMessage.ProtoObjectList) { var objIx = msgTuple.Item1.ProtoType; var objHandlers = this.handlers[objIx]; Debug.Log($"Obj Type {objIx}, handler count {objHandlers.Count}"); foreach (var methodAndObj in objHandlers) { var methodToCall = methodAndObj.Item1; var objToCall = methodAndObj.Item2; Debug.Log($"Promising to send the object to {objToCall.GetType().Name}"); allPromises.Add((Promise <ProtoMessage>)methodToCall.Invoke(objToCall, new object[] { msgTuple.Item2 })); } } //here we guarantee to return eventually -- so this can be async handled //first fullfill all of our promises, //then take the collection of results and merge them into a single return message return(Promise <ProtoMessage> .All(allPromises) .Then(protoCollection => { Debug.Log("All messages routed and responded to"); return mergePromise(protoCollection); })); }
//merge in another message public ProtoMessage AddProtoObjects(ProtoMessage other) { this.AddProtoObjects(other.ProtoObjectList); return(this); }
// Here we simply decode our byte buffer into a collection of proto objects // then we return a holder of all the proto objects, to be processed elsewhere (the router) public ProtoMessage DecodeByteToProto(byte[] byteArray) { ProtoMessage incomingMessage = new ProtoMessage(); ByteOperations.ByteReader byteBuffer = new ByteOperations.ByteReader(byteArray); try { Debug.Log($"littel end {BitConverter.IsLittleEndian}"); //get info about the header Int32 headerLength = byteBuffer.ReadInt(); Debug.Log($"Reading header of size: {headerLength}, total size: {byteBuffer.Length}"); var header = byteBuffer.ReadBytes(headerLength); // parse out the header information from the above clue var protoHeader = ProtoHeader.Parser.ParseFrom(header.ToArray()); Debug.Log($"header len: {headerLength}, 'val' : {protoHeader}"); // now we have a list of objects in our header, and we can ready each length foreach (var protoItem in protoHeader.ProtoItems) { var pid = protoItem.ProtoId; var pType = protoItem.ProtoType; var readLength = protoItem.ProtoSize; Debug.Log($"Reading next item: obj id: {pid} type: {pType}, length: {readLength}"); //get our next object bytes according to sizes var nextObjectBytes = byteBuffer.ReadBytes(readLength); //use our type info to get the static parser and parse //from the bytes we just read //get the static parser property var parserInfo = ixToClass[pType].GetProperty("Parser", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); Debug.Log($"Reading next item: type: {ixToClass[pType]}"); Debug.Log($"Reading next item parser: {ixToClass[pType].GetProperty("Parser", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)}"); //get the ParseFrom internal method in the protobuf message class var parseStringMethod = parserInfo.PropertyType.GetMethod("ParseFrom", new[] { typeof(byte[]) }); Debug.Log($"Reading next item parse method: {parseStringMethod}"); //get the static parser object parser = parserInfo.GetValue(null, null); //now actuall parse from the bytes var obj = parseStringMethod.Invoke(parser, new object[] { nextObjectBytes }); var objType = obj.GetType(); incomingMessage.AddProtoObject(protoItem, obj); Debug.Log($"Finished item #{pid}, type: {pType}, length: {readLength}, parsed obj: {obj}"); } } catch (Exception e) { Debug.Log($"exception reading {e}"); Debug.Log($"exception reading ST: {e.StackTrace}"); } // send back the message with all the proto objects inside Debug.Log("Finished deconstructing message"); return(incomingMessage); }