Home | History | Annotate | Download | only in inspector
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include "core/inspector/InspectorWorkerAgent.h"
     34 
     35 #include "core/InspectorFrontend.h"
     36 #include "core/inspector/InspectorState.h"
     37 #include "core/inspector/InstrumentingAgents.h"
     38 #include "core/inspector/JSONParser.h"
     39 #include "core/workers/WorkerGlobalScopeProxy.h"
     40 #include "platform/JSONValues.h"
     41 #include "platform/weborigin/KURL.h"
     42 #include "wtf/PassOwnPtr.h"
     43 #include "wtf/RefPtr.h"
     44 
     45 namespace WebCore {
     46 
     47 namespace WorkerAgentState {
     48 static const char workerInspectionEnabled[] = "workerInspectionEnabled";
     49 static const char autoconnectToWorkers[] = "autoconnectToWorkers";
     50 };
     51 
     52 class InspectorWorkerAgent::WorkerFrontendChannel FINAL : public WorkerGlobalScopeProxy::PageInspector {
     53     WTF_MAKE_FAST_ALLOCATED;
     54 public:
     55     explicit WorkerFrontendChannel(InspectorFrontend* frontend, WorkerGlobalScopeProxy* proxy)
     56         : m_frontend(frontend)
     57         , m_proxy(proxy)
     58         , m_id(s_nextId++)
     59         , m_connected(false)
     60     {
     61     }
     62     virtual ~WorkerFrontendChannel()
     63     {
     64         disconnectFromWorkerGlobalScope();
     65     }
     66 
     67     int id() const { return m_id; }
     68     WorkerGlobalScopeProxy* proxy() const { return m_proxy; }
     69 
     70     void connectToWorkerGlobalScope()
     71     {
     72         if (m_connected)
     73             return;
     74         m_connected = true;
     75         m_proxy->connectToInspector(this);
     76     }
     77 
     78     void disconnectFromWorkerGlobalScope()
     79     {
     80         if (!m_connected)
     81             return;
     82         m_connected = false;
     83         m_proxy->disconnectFromInspector();
     84     }
     85 
     86 private:
     87     // WorkerGlobalScopeProxy::PageInspector implementation
     88     virtual void dispatchMessageFromWorker(const String& message) OVERRIDE
     89     {
     90         RefPtr<JSONValue> value = parseJSON(message);
     91         if (!value)
     92             return;
     93         RefPtr<JSONObject> messageObject = value->asObject();
     94         if (!messageObject)
     95             return;
     96         m_frontend->worker()->dispatchMessageFromWorker(m_id, messageObject);
     97     }
     98 
     99     InspectorFrontend* m_frontend;
    100     WorkerGlobalScopeProxy* m_proxy;
    101     int m_id;
    102     bool m_connected;
    103     static int s_nextId;
    104 };
    105 
    106 int InspectorWorkerAgent::WorkerFrontendChannel::s_nextId = 1;
    107 
    108 PassOwnPtr<InspectorWorkerAgent> InspectorWorkerAgent::create()
    109 {
    110     return adoptPtr(new InspectorWorkerAgent());
    111 }
    112 
    113 InspectorWorkerAgent::InspectorWorkerAgent()
    114     : InspectorBaseAgent<InspectorWorkerAgent>("Worker")
    115     , m_inspectorFrontend(0)
    116 {
    117 }
    118 
    119 InspectorWorkerAgent::~InspectorWorkerAgent()
    120 {
    121     m_instrumentingAgents->setInspectorWorkerAgent(0);
    122 }
    123 
    124 void InspectorWorkerAgent::init()
    125 {
    126     m_instrumentingAgents->setInspectorWorkerAgent(this);
    127 }
    128 
    129 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend)
    130 {
    131     m_inspectorFrontend = frontend;
    132 }
    133 
    134 void InspectorWorkerAgent::restore()
    135 {
    136     if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    137         createWorkerFrontendChannelsForExistingWorkers();
    138 }
    139 
    140 void InspectorWorkerAgent::clearFrontend()
    141 {
    142     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false);
    143     disable(0);
    144     m_inspectorFrontend = 0;
    145 }
    146 
    147 void InspectorWorkerAgent::enable(ErrorString*)
    148 {
    149     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true);
    150     if (!m_inspectorFrontend)
    151         return;
    152     createWorkerFrontendChannelsForExistingWorkers();
    153 }
    154 
    155 void InspectorWorkerAgent::disable(ErrorString*)
    156 {
    157     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false);
    158     if (!m_inspectorFrontend)
    159         return;
    160     destroyWorkerFrontendChannels();
    161 }
    162 
    163 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result)
    164 {
    165     *result = true;
    166 }
    167 
    168 void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId)
    169 {
    170     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    171     if (channel)
    172         channel->connectToWorkerGlobalScope();
    173     else
    174         *error = "Worker is gone";
    175 }
    176 
    177 void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId)
    178 {
    179     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    180     if (channel)
    181         channel->disconnectFromWorkerGlobalScope();
    182     else
    183         *error = "Worker is gone";
    184 }
    185 
    186 void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<JSONObject>& message)
    187 {
    188     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    189     if (channel)
    190         channel->proxy()->sendMessageToInspector(message->toJSONString());
    191     else
    192         *error = "Worker is gone";
    193 }
    194 
    195 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value)
    196 {
    197     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value);
    198 }
    199 
    200 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart()
    201 {
    202     return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    203 }
    204 
    205 void InspectorWorkerAgent::didStartWorkerGlobalScope(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const KURL& url)
    206 {
    207     m_dedicatedWorkers.set(workerGlobalScopeProxy, url.string());
    208     if (m_inspectorFrontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    209         createWorkerFrontendChannel(workerGlobalScopeProxy, url.string());
    210 }
    211 
    212 void InspectorWorkerAgent::workerGlobalScopeTerminated(WorkerGlobalScopeProxy* proxy)
    213 {
    214     m_dedicatedWorkers.remove(proxy);
    215     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    216         if (proxy == it->value->proxy()) {
    217             m_inspectorFrontend->worker()->workerTerminated(it->key);
    218             delete it->value;
    219             m_idToChannel.remove(it);
    220             return;
    221         }
    222     }
    223 }
    224 
    225 void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers()
    226 {
    227     for (DedicatedWorkers::iterator it = m_dedicatedWorkers.begin(); it != m_dedicatedWorkers.end(); ++it)
    228         createWorkerFrontendChannel(it->key, it->value);
    229 }
    230 
    231 void InspectorWorkerAgent::destroyWorkerFrontendChannels()
    232 {
    233     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    234         it->value->disconnectFromWorkerGlobalScope();
    235         delete it->value;
    236     }
    237     m_idToChannel.clear();
    238 }
    239 
    240 void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const String& url)
    241 {
    242     WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_inspectorFrontend, workerGlobalScopeProxy);
    243     m_idToChannel.set(channel->id(), channel);
    244 
    245     ASSERT(m_inspectorFrontend);
    246     bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    247     if (autoconnectToWorkers)
    248         channel->connectToWorkerGlobalScope();
    249     m_inspectorFrontend->worker()->workerCreated(channel->id(), url, autoconnectToWorkers);
    250 }
    251 
    252 } // namespace WebCore
    253