public static MessageData DecodeMessage(ZMessage message) => new MessageData { Identity = message.Pop().ReadInt32(), Type = (MessageType)message.Pop().ReadAsByte(), Data = message.Select((frame) => frame.Read()).ToArray() };
public void Pop() { const string test1 = "__TEST1__", test2 = "__TEST2__"; var msg = new ZMessage { new ZFrame(test1), new ZFrame(test2) }; var frame = msg.Pop(); Assert.AreEqual(0, frame.Position); Assert.AreEqual(new ZFrame(test1), frame); }
// .split try to call a service // Here, we first check if the requested MDP service is defined or not, // using a MMI lookup to the Majordomo broker. If the service exists, // we send a request and wait for a reply using the conventional MDP // client API. This is not meant to be fast, just very simple: static bool Titanic_ServiceSuccess(Guid uuid, CancellationTokenSource cts) { // Load request message, service will be first frame string fn = TitanicCommon.RequestFilename(uuid); FileStream fs; if (!fn.TryFileOpenRead(out fs)) { // If the client already close request, treat as successful return(true); } fs.Dispose(); ZMessage request = fn.DeserializeFromXml <ZMessage>(); var service = request.Pop(); string servicename = service.ToString(); bool res = false; // Create MDP client session with short timeout using (var client = new MajordomoClient("tcp://127.0.0.1:5555", false)) { client.Set_Timeout(1000); // 1sec client.Set_Retries(1); // only 1 retry // Use MMI protocol to check if service is available ZMessage mmirequest = new ZMessage { service }; bool service_ok; using (var mmireply = client.Send("mmi.service", mmirequest, cts)) service_ok = (mmireply != null && mmireply.First().ToString().Equals("200")); res = false; if (service_ok) { using (ZMessage reply = client.Send(servicename, request, cts)) if (reply != null) { fn = TitanicCommon.ReplyFilename(uuid); reply.SerializeToXml(fn); res = true; } else { request.Dispose(); } } } return(res); }
public void RouterMessage(ZMessage reply) { // This method processes one message from a connected // server: // Frame 0 is server that replied string endpoint; using (var endpointFrame = reply.Pop()) { endpoint = endpointFrame.ReadString(); } Server server = this.Servers.Single(s => s.Endpoint == endpoint); if (!server.Alive) { this.Actives.Add(server); server.Refresh(true); } // Frame 1 may be sequence number for reply int sequence; using (var sequenceFrame = reply.Pop()) { sequence = sequenceFrame.ReadInt32(); } if (sequence == this.sequence) { reply.Prepend(new ZFrame("OK")); this.Pipe.Send(reply); this.Request.Dispose(); this.Request = null; } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if (msg.Count < 2) { throw new InvalidOperationException(); } using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else { returnCode = "501"; } var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
public void ControlMessage(ZMessage msg) { // This method processes one message from our frontend class // (it's going to be CONNECT or REQUEST): string command; using (var commandFrame = msg.Pop()) { command = commandFrame.ReadString(); } if (command == "CONNECT") { string endpoint = msg[0].ReadString(); Console.WriteLine("I: connecting to {0}...", endpoint); Router.Connect(endpoint); var server = new Server(endpoint); this.Servers.Add(server); this.Actives.Add(server); } else if (command == "REQUEST") { if (this.Request != null) { // Strict request-reply cycle throw new InvalidOperationException(); } // Prefix request with sequence number and empty envelope msg.Prepend(new ZFrame(++sequence)); // Take ownership of request message this.Request = msg.Duplicate(); // Request expires after global timeout this.Expires = DateTime.UtcNow + GLOBAL_TIMEOUT; } }
// .split Titanic close task // The {{titanic.close}} task removes any waiting replies for the request // (specified by UUID). It's idempotent, so it is safe to call more than // once in a row: private static void Titanic_Close(ZContext context, CancellationTokenSource cts, bool verbose) { using (var worker = new MajordomoWorker("tcp://127.0.0.1:5555", "titanic.close", verbose)) { ZMessage reply = null; while (true) { ZMessage request = worker.Recv(reply, cts); if (request == null) { break; } var g = Guid.Parse(request.Pop().ReadString()); var reqfn = TitanicCommon.RequestFilename(g); var repfn = TitanicCommon.ReplyFilename(g); File.Delete(reqfn); File.Delete(repfn); request.Dispose(); reply = new ZMessage(); reply.Add(new ZFrame("200")); } } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else returnCode = "501"; var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if(msg.Count < 1) // At least, command throw new InvalidOperationException(); ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) // Not first command in session worker.Delete(true); else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) // Reserd servicee name worker.Delete(true); else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) worker.Delete(false); else { msg.DumpZmsg("E: invalid input message"); } } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "400"; } else returnCode = "501"; using (var resetableFrame = msg.Pop()) { msg.Prepend(new ZFrame(returnCode)); } //ToDo check c implementation throw new NotImplementedException("ToDo: fix this section, never tested. contains errors mmi services never called with the mdclient/mdbroker/mdworker examples"); //## following code has some errors // Remove & save client return envelope and insert the // protocol header and Service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if (msg.Count < 1) // At least, command { throw new InvalidOperationException(); } ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) { // Not first command in session worker.Delete(true); } else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) { // Reserd servicee name worker.Delete(true); } else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) { worker.Delete(false); } else { msg.DumpZmsg("E: invalid input message"); } } }