// This file is generated by TypeBuilder_cpp.template.

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/devtools/protocol/service_worker.h"

#include "content/browser/devtools/protocol/protocol.h"

#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/find_by_first.h"
#include "third_party/inspector_protocol/crdtp/span.h"

namespace content {
namespace protocol {
namespace ServiceWorker {

using crdtp::DeserializerState;
using crdtp::FallthroughCallback;
using crdtp::ProtocolTypeTraits;

// ------------- Enum values from types.

const char Metainfo::domainName[] = "ServiceWorker";
const char Metainfo::commandPrefix[] = "ServiceWorker.";
const char Metainfo::version[] = "1.3";


CRDTP_BEGIN_DESERIALIZER(ServiceWorkerRegistration)
    CRDTP_DESERIALIZE_FIELD("isDeleted", m_isDeleted),
    CRDTP_DESERIALIZE_FIELD("registrationId", m_registrationId),
    CRDTP_DESERIALIZE_FIELD("scopeURL", m_scopeURL),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerRegistration)
    CRDTP_SERIALIZE_FIELD("registrationId", m_registrationId);
    CRDTP_SERIALIZE_FIELD("scopeURL", m_scopeURL);
    CRDTP_SERIALIZE_FIELD("isDeleted", m_isDeleted);
CRDTP_END_SERIALIZER();




CRDTP_BEGIN_DESERIALIZER(ServiceWorkerRouterCondition)
    CRDTP_DESERIALIZE_FIELD_OPT("requestDestination", m_requestDestination),
    CRDTP_DESERIALIZE_FIELD_OPT("requestMethod", m_requestMethod),
    CRDTP_DESERIALIZE_FIELD_OPT("requestMode", m_requestMode),
    CRDTP_DESERIALIZE_FIELD_OPT("runningStatus", m_runningStatus),
    CRDTP_DESERIALIZE_FIELD_OPT("urlPattern", m_urlPattern),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerRouterCondition)
    CRDTP_SERIALIZE_FIELD("urlPattern", m_urlPattern);
    CRDTP_SERIALIZE_FIELD("requestMethod", m_requestMethod);
    CRDTP_SERIALIZE_FIELD("requestMode", m_requestMode);
    CRDTP_SERIALIZE_FIELD("requestDestination", m_requestDestination);
    CRDTP_SERIALIZE_FIELD("runningStatus", m_runningStatus);
CRDTP_END_SERIALIZER();



CRDTP_BEGIN_DESERIALIZER(ServiceWorkerRouterSourceDict)
    CRDTP_DESERIALIZE_FIELD("cacheName", m_cacheName),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerRouterSourceDict)
    CRDTP_SERIALIZE_FIELD("cacheName", m_cacheName);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ServiceWorkerRouterSource)
    CRDTP_DESERIALIZE_FIELD_OPT("sourceDict", m_sourceDict),
    CRDTP_DESERIALIZE_FIELD("type", m_type),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerRouterSource)
    CRDTP_SERIALIZE_FIELD("type", m_type);
    CRDTP_SERIALIZE_FIELD("sourceDict", m_sourceDict);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ServiceWorkerRouterRule)
    CRDTP_DESERIALIZE_FIELD("condition", m_condition),
    CRDTP_DESERIALIZE_FIELD("id", m_id),
    CRDTP_DESERIALIZE_FIELD("source", m_source),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerRouterRule)
    CRDTP_SERIALIZE_FIELD("condition", m_condition);
    CRDTP_SERIALIZE_FIELD("source", m_source);
    CRDTP_SERIALIZE_FIELD("id", m_id);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ServiceWorkerVersion)
    CRDTP_DESERIALIZE_FIELD_OPT("controlledClients", m_controlledClients),
    CRDTP_DESERIALIZE_FIELD("registrationId", m_registrationId),
    CRDTP_DESERIALIZE_FIELD_OPT("routerRules", m_routerRules),
    CRDTP_DESERIALIZE_FIELD("runningStatus", m_runningStatus),
    CRDTP_DESERIALIZE_FIELD_OPT("scriptLastModified", m_scriptLastModified),
    CRDTP_DESERIALIZE_FIELD_OPT("scriptResponseTime", m_scriptResponseTime),
    CRDTP_DESERIALIZE_FIELD("scriptURL", m_scriptURL),
    CRDTP_DESERIALIZE_FIELD("status", m_status),
    CRDTP_DESERIALIZE_FIELD_OPT("targetId", m_targetId),
    CRDTP_DESERIALIZE_FIELD_OPT("typedRouterRules", m_typedRouterRules),
    CRDTP_DESERIALIZE_FIELD("versionId", m_versionId),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerVersion)
    CRDTP_SERIALIZE_FIELD("versionId", m_versionId);
    CRDTP_SERIALIZE_FIELD("registrationId", m_registrationId);
    CRDTP_SERIALIZE_FIELD("scriptURL", m_scriptURL);
    CRDTP_SERIALIZE_FIELD("runningStatus", m_runningStatus);
    CRDTP_SERIALIZE_FIELD("status", m_status);
    CRDTP_SERIALIZE_FIELD("scriptLastModified", m_scriptLastModified);
    CRDTP_SERIALIZE_FIELD("scriptResponseTime", m_scriptResponseTime);
    CRDTP_SERIALIZE_FIELD("controlledClients", m_controlledClients);
    CRDTP_SERIALIZE_FIELD("targetId", m_targetId);
    CRDTP_SERIALIZE_FIELD("routerRules", m_routerRules);
    CRDTP_SERIALIZE_FIELD("typedRouterRules", m_typedRouterRules);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(ServiceWorkerErrorMessage)
    CRDTP_DESERIALIZE_FIELD("columnNumber", m_columnNumber),
    CRDTP_DESERIALIZE_FIELD("errorMessage", m_errorMessage),
    CRDTP_DESERIALIZE_FIELD("lineNumber", m_lineNumber),
    CRDTP_DESERIALIZE_FIELD("registrationId", m_registrationId),
    CRDTP_DESERIALIZE_FIELD("sourceURL", m_sourceURL),
    CRDTP_DESERIALIZE_FIELD("versionId", m_versionId),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(ServiceWorkerErrorMessage)
    CRDTP_SERIALIZE_FIELD("errorMessage", m_errorMessage);
    CRDTP_SERIALIZE_FIELD("registrationId", m_registrationId);
    CRDTP_SERIALIZE_FIELD("versionId", m_versionId);
    CRDTP_SERIALIZE_FIELD("sourceURL", m_sourceURL);
    CRDTP_SERIALIZE_FIELD("lineNumber", m_lineNumber);
    CRDTP_SERIALIZE_FIELD("columnNumber", m_columnNumber);
CRDTP_END_SERIALIZER();


// ------------- Enum values from params.


// ------------- Frontend notifications.

void Frontend::WorkerErrorReported(std::unique_ptr<protocol::ServiceWorker::ServiceWorkerErrorMessage> errorMessage)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("errorMessage"), errorMessage);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("ServiceWorker.workerErrorReported", serializer.Finish()));
}

void Frontend::WorkerRegistrationUpdated(std::unique_ptr<protocol::Array<protocol::ServiceWorker::ServiceWorkerRegistration>> registrations)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("registrations"), registrations);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("ServiceWorker.workerRegistrationUpdated", serializer.Finish()));
}

void Frontend::WorkerVersionUpdated(std::unique_ptr<protocol::Array<protocol::ServiceWorker::ServiceWorkerVersion>> versions)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("versions"), versions);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("ServiceWorker.workerVersionUpdated", serializer.Finish()));
}

void Frontend::flush()
{
    frontend_channel_->FlushProtocolNotifications();
}

void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
{
    frontend_channel_->SendProtocolNotification(std::move(notification));
}

// --------------------- Dispatcher.

class DomainDispatcherImpl : public protocol::DomainDispatcher {
public:
    DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
        : DomainDispatcher(frontendChannel)
        , m_backend(backend) {}
    ~DomainDispatcherImpl() override { }

    using CallHandler = void (DomainDispatcherImpl::*)(crdtp::Dispatchable& dispatchable);

    bool Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) override;

    void deliverPushMessage(crdtp::Dispatchable& dispatchable);
    void disable(crdtp::Dispatchable& dispatchable);
    void dispatchSyncEvent(crdtp::Dispatchable& dispatchable);
    void dispatchPeriodicSyncEvent(crdtp::Dispatchable& dispatchable);
    void enable(crdtp::Dispatchable& dispatchable);
    void setForceUpdateOnPageLoad(crdtp::Dispatchable& dispatchable);
    void skipWaiting(crdtp::Dispatchable& dispatchable);
    void startWorker(crdtp::Dispatchable& dispatchable);
    void stopAllWorkers(crdtp::Dispatchable& dispatchable);
    void stopWorker(crdtp::Dispatchable& dispatchable);
    void unregister(crdtp::Dispatchable& dispatchable);
    void updateRegistration(crdtp::Dispatchable& dispatchable);
 protected:
    Backend* m_backend;
};

namespace {
// This helper method with a static map of command methods (instance methods
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
// in the DomainDispatcherImpl::Dispatch method.
DomainDispatcherImpl::CallHandler CommandByName(crdtp::span<uint8_t> command_name) {
  static auto* commands = [](){
    auto* commands = new std::vector<std::pair<crdtp::span<uint8_t>,
                              DomainDispatcherImpl::CallHandler>>{
    {
          crdtp::SpanFrom("deliverPushMessage"),
          &DomainDispatcherImpl::deliverPushMessage
    },
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("dispatchPeriodicSyncEvent"),
          &DomainDispatcherImpl::dispatchPeriodicSyncEvent
    },
    {
          crdtp::SpanFrom("dispatchSyncEvent"),
          &DomainDispatcherImpl::dispatchSyncEvent
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("setForceUpdateOnPageLoad"),
          &DomainDispatcherImpl::setForceUpdateOnPageLoad
    },
    {
          crdtp::SpanFrom("skipWaiting"),
          &DomainDispatcherImpl::skipWaiting
    },
    {
          crdtp::SpanFrom("startWorker"),
          &DomainDispatcherImpl::startWorker
    },
    {
          crdtp::SpanFrom("stopAllWorkers"),
          &DomainDispatcherImpl::stopAllWorkers
    },
    {
          crdtp::SpanFrom("stopWorker"),
          &DomainDispatcherImpl::stopWorker
    },
    {
          crdtp::SpanFrom("unregister"),
          &DomainDispatcherImpl::unregister
    },
    {
          crdtp::SpanFrom("updateRegistration"),
          &DomainDispatcherImpl::updateRegistration
    },
    };
    return commands;
  }();
  return crdtp::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
}
}  // namespace

bool DomainDispatcherImpl::Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) {
  CallHandler handler = CommandByName(command_name);
  if (!handler) return false;

  (this->*handler)(dispatchable);
  return true;
}


namespace {

struct deliverPushMessageParams : public crdtp::DeserializableProtocolObject<deliverPushMessageParams> {
    String origin;
    String registrationId;
    String data;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(deliverPushMessageParams)
    CRDTP_DESERIALIZE_FIELD("data", data),
    CRDTP_DESERIALIZE_FIELD("origin", origin),
    CRDTP_DESERIALIZE_FIELD("registrationId", registrationId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::deliverPushMessage(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    deliverPushMessageParams params;
    if (!deliverPushMessageParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->DeliverPushMessage(params.origin, params.registrationId, params.data);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::disable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Disable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct dispatchSyncEventParams : public crdtp::DeserializableProtocolObject<dispatchSyncEventParams> {
    String origin;
    String registrationId;
    String tag;
    bool lastChance;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(dispatchSyncEventParams)
    CRDTP_DESERIALIZE_FIELD("lastChance", lastChance),
    CRDTP_DESERIALIZE_FIELD("origin", origin),
    CRDTP_DESERIALIZE_FIELD("registrationId", registrationId),
    CRDTP_DESERIALIZE_FIELD("tag", tag),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::dispatchSyncEvent(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    dispatchSyncEventParams params;
    if (!dispatchSyncEventParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->DispatchSyncEvent(params.origin, params.registrationId, params.tag, params.lastChance);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct dispatchPeriodicSyncEventParams : public crdtp::DeserializableProtocolObject<dispatchPeriodicSyncEventParams> {
    String origin;
    String registrationId;
    String tag;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(dispatchPeriodicSyncEventParams)
    CRDTP_DESERIALIZE_FIELD("origin", origin),
    CRDTP_DESERIALIZE_FIELD("registrationId", registrationId),
    CRDTP_DESERIALIZE_FIELD("tag", tag),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::dispatchPeriodicSyncEvent(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    dispatchPeriodicSyncEventParams params;
    if (!dispatchPeriodicSyncEventParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->DispatchPeriodicSyncEvent(params.origin, params.registrationId, params.tag);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::enable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Enable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct setForceUpdateOnPageLoadParams : public crdtp::DeserializableProtocolObject<setForceUpdateOnPageLoadParams> {
    bool forceUpdateOnPageLoad;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setForceUpdateOnPageLoadParams)
    CRDTP_DESERIALIZE_FIELD("forceUpdateOnPageLoad", forceUpdateOnPageLoad),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::setForceUpdateOnPageLoad(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    setForceUpdateOnPageLoadParams params;
    if (!setForceUpdateOnPageLoadParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetForceUpdateOnPageLoad(params.forceUpdateOnPageLoad);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct skipWaitingParams : public crdtp::DeserializableProtocolObject<skipWaitingParams> {
    String scopeURL;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(skipWaitingParams)
    CRDTP_DESERIALIZE_FIELD("scopeURL", scopeURL),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::skipWaiting(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    skipWaitingParams params;
    if (!skipWaitingParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SkipWaiting(params.scopeURL);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct startWorkerParams : public crdtp::DeserializableProtocolObject<startWorkerParams> {
    String scopeURL;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(startWorkerParams)
    CRDTP_DESERIALIZE_FIELD("scopeURL", scopeURL),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::startWorker(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    startWorkerParams params;
    if (!startWorkerParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->StartWorker(params.scopeURL);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

class StopAllWorkersCallbackImpl : public Backend::StopAllWorkersCallback, public DomainDispatcher::Callback {
public:
    StopAllWorkersCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("ServiceWorker.stopAllWorkers")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {


}  // namespace

void DomainDispatcherImpl::stopAllWorkers(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    m_backend->StopAllWorkers(std::make_unique<StopAllWorkersCallbackImpl>(weakPtr(), dispatchable));
}

namespace {

struct stopWorkerParams : public crdtp::DeserializableProtocolObject<stopWorkerParams> {
    String versionId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(stopWorkerParams)
    CRDTP_DESERIALIZE_FIELD("versionId", versionId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::stopWorker(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    stopWorkerParams params;
    if (!stopWorkerParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->StopWorker(params.versionId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct unregisterParams : public crdtp::DeserializableProtocolObject<unregisterParams> {
    String scopeURL;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(unregisterParams)
    CRDTP_DESERIALIZE_FIELD("scopeURL", scopeURL),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::unregister(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    unregisterParams params;
    if (!unregisterParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Unregister(params.scopeURL);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct updateRegistrationParams : public crdtp::DeserializableProtocolObject<updateRegistrationParams> {
    String scopeURL;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(updateRegistrationParams)
    CRDTP_DESERIALIZE_FIELD("scopeURL", scopeURL),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::updateRegistration(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    updateRegistrationParams params;
    if (!updateRegistrationParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->UpdateRegistration(params.scopeURL);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {
// This helper method (with a static map of redirects) is used from Dispatcher::wire
// immediately below.
const std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>& SortedRedirects() {
  static auto* redirects = [](){
    auto* redirects = new std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>{
    };
    return redirects;
  }();
  return *redirects;
}
}  // namespace

// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
    auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
    uber->WireBackend(crdtp::SpanFrom("ServiceWorker"), SortedRedirects(), std::move(dispatcher));
}

} // ServiceWorker
} // namespace content
} // namespace protocol
