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 "InspectorFrontend.h"
     36 #include "core/inspector/InspectorState.h"
     37 #include "core/inspector/InstrumentingAgents.h"
     38 #include "core/inspector/JSONParser.h"
     39 #include "core/platform/JSONValues.h"
     40 #include "core/workers/WorkerGlobalScopeProxy.h"
     41 #include "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 : 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)
     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(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
    109 {
    110     return adoptPtr(new InspectorWorkerAgent(instrumentingAgents, inspectorState));
    111 }
    112 
    113 InspectorWorkerAgent::InspectorWorkerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState)
    114     : InspectorBaseAgent<InspectorWorkerAgent>("Worker", instrumentingAgents, inspectorState)
    115     , m_inspectorFrontend(0)
    116 {
    117     m_instrumentingAgents->setInspectorWorkerAgent(this);
    118 }
    119 
    120 InspectorWorkerAgent::~InspectorWorkerAgent()
    121 {
    122     m_instrumentingAgents->setInspectorWorkerAgent(0);
    123 }
    124 
    125 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend)
    126 {
    127     m_inspectorFrontend = frontend;
    128 }
    129 
    130 void InspectorWorkerAgent::restore()
    131 {
    132     if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    133         createWorkerFrontendChannelsForExistingWorkers();
    134 }
    135 
    136 void InspectorWorkerAgent::clearFrontend()
    137 {
    138     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false);
    139     disable(0);
    140     m_inspectorFrontend = 0;
    141 }
    142 
    143 void InspectorWorkerAgent::enable(ErrorString*)
    144 {
    145     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true);
    146     if (!m_inspectorFrontend)
    147         return;
    148     createWorkerFrontendChannelsForExistingWorkers();
    149 }
    150 
    151 void InspectorWorkerAgent::disable(ErrorString*)
    152 {
    153     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false);
    154     if (!m_inspectorFrontend)
    155         return;
    156     destroyWorkerFrontendChannels();
    157 }
    158 
    159 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result)
    160 {
    161     *result = true;
    162 }
    163 
    164 void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId)
    165 {
    166     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    167     if (channel)
    168         channel->connectToWorkerGlobalScope();
    169     else
    170         *error = "Worker is gone";
    171 }
    172 
    173 void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId)
    174 {
    175     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    176     if (channel)
    177         channel->disconnectFromWorkerGlobalScope();
    178     else
    179         *error = "Worker is gone";
    180 }
    181 
    182 void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<JSONObject>& message)
    183 {
    184     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    185     if (channel)
    186         channel->proxy()->sendMessageToInspector(message->toJSONString());
    187     else
    188         *error = "Worker is gone";
    189 }
    190 
    191 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value)
    192 {
    193     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value);
    194 }
    195 
    196 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart()
    197 {
    198     return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    199 }
    200 
    201 void InspectorWorkerAgent::didStartWorkerGlobalScope(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const KURL& url)
    202 {
    203     m_dedicatedWorkers.set(workerGlobalScopeProxy, url.string());
    204     if (m_inspectorFrontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    205         createWorkerFrontendChannel(workerGlobalScopeProxy, url.string());
    206 }
    207 
    208 void InspectorWorkerAgent::workerGlobalScopeTerminated(WorkerGlobalScopeProxy* proxy)
    209 {
    210     m_dedicatedWorkers.remove(proxy);
    211     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    212         if (proxy == it->value->proxy()) {
    213             m_inspectorFrontend->worker()->workerTerminated(it->key);
    214             delete it->value;
    215             m_idToChannel.remove(it);
    216             return;
    217         }
    218     }
    219 }
    220 
    221 void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers()
    222 {
    223     for (DedicatedWorkers::iterator it = m_dedicatedWorkers.begin(); it != m_dedicatedWorkers.end(); ++it)
    224         createWorkerFrontendChannel(it->key, it->value);
    225 }
    226 
    227 void InspectorWorkerAgent::destroyWorkerFrontendChannels()
    228 {
    229     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    230         it->value->disconnectFromWorkerGlobalScope();
    231         delete it->value;
    232     }
    233     m_idToChannel.clear();
    234 }
    235 
    236 void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const String& url)
    237 {
    238     WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_inspectorFrontend, workerGlobalScopeProxy);
    239     m_idToChannel.set(channel->id(), channel);
    240 
    241     ASSERT(m_inspectorFrontend);
    242     bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    243     if (autoconnectToWorkers)
    244         channel->connectToWorkerGlobalScope();
    245     m_inspectorFrontend->worker()->workerCreated(channel->id(), url, autoconnectToWorkers);
    246 }
    247 
    248 } // namespace WebCore
    249