public Topper(string jsonString)
        {
            Topper message = JsonUtility.FromJson <Topper>(jsonString);

            op    = message.op;
            topic = message.topic;
        }
        private void OnMessage(string s)
        {
            if ((s != null) && !s.Equals(""))
            {
                Topper mms = new Topper(s);

                string op = mms.op;

                if ("publish".Equals(op))
                {
                    string topic      = mms.topic;
                    string msg_params = "";

                    // if we have message parameters, parse them
                    Match      m   = Regex.Match(s, @"""msg""\s*:\s*({.*}),");
                    ROSMessage msg = null;
                    if (m.Success)
                    {
                        msg_params = m.Groups[1].Value;
                    }

                    foreach (var sub in _subscribers)
                    {
                        // only consider subscribers with a matching topic
                        if (topic != sub.Key.topic)
                        {
                            continue;
                        }

                        msg = sub.Key.ParseMessage(msg_params);
                        MessageTask newTask = new MessageTask(sub.Key, msg);
                        lock (_readLock)
                        {
                            _msgQueue[topic].Enqueue(newTask);
                        }
                    }
                }
                else if (Regex.IsMatch(s, @"""op""\s*:\s*""call_service""")) // op is call_service
                {
                    ServiceHeader hdr = new ServiceHeader(s);
                    foreach (var srv in _serviceServers)
                    {
                        if (srv.Key.topic == hdr.service)
                        {
                            ServiceArgs     args     = null;
                            ServiceResponse response = null;
                            // if we have args, parse them (args are optional on services, though)
                            Match m = Regex.Match(s, @"""args""\s*:\s*({.*}),");
                            if (m.Success)
                            {
                                args = srv.Key.ParseRequest(m.Groups[1].Value);
                            }

                            // add service request to queue, to be processed later in Render()
                            lock (_readLock)
                            {
                                _svcQueue[srv.Key.topic].Enqueue(new ServiceTask(srv.Key, args, hdr.id));
                            }

                            break; // there should only be one server for each service
                        }
                    }
                }
                else
                {
                    Debug.LogWarning("Unhandled message:\n" + s);
                }
            }
            else
            {
                Debug.Log("Got an empty message from the web socket");
            }
        }