michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsTransportUtils.h" michael@0: #include "nsITransport.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsTransportStatusEvent; michael@0: michael@0: class nsTransportEventSinkProxy : public nsITransportEventSink michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSITRANSPORTEVENTSINK michael@0: michael@0: nsTransportEventSinkProxy(nsITransportEventSink *sink, michael@0: nsIEventTarget *target, michael@0: bool coalesceAll) michael@0: : mSink(sink) michael@0: , mTarget(target) michael@0: , mLock("nsTransportEventSinkProxy.mLock") michael@0: , mLastEvent(nullptr) michael@0: , mCoalesceAll(coalesceAll) michael@0: { michael@0: NS_ADDREF(mSink); michael@0: } michael@0: michael@0: virtual ~nsTransportEventSinkProxy() michael@0: { michael@0: // our reference to mSink could be the last, so be sure to release michael@0: // it on the target thread. otherwise, we could get into trouble. michael@0: NS_ProxyRelease(mTarget, mSink); michael@0: } michael@0: michael@0: nsITransportEventSink *mSink; michael@0: nsCOMPtr mTarget; michael@0: Mutex mLock; michael@0: nsTransportStatusEvent *mLastEvent; michael@0: bool mCoalesceAll; michael@0: }; michael@0: michael@0: class nsTransportStatusEvent : public nsRunnable michael@0: { michael@0: public: michael@0: nsTransportStatusEvent(nsTransportEventSinkProxy *proxy, michael@0: nsITransport *transport, michael@0: nsresult status, michael@0: uint64_t progress, michael@0: uint64_t progressMax) michael@0: : mProxy(proxy) michael@0: , mTransport(transport) michael@0: , mStatus(status) michael@0: , mProgress(progress) michael@0: , mProgressMax(progressMax) michael@0: {} michael@0: michael@0: ~nsTransportStatusEvent() {} michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: // since this event is being handled, we need to clear the proxy's ref. michael@0: // if not coalescing all, then last event may not equal self! michael@0: { michael@0: MutexAutoLock lock(mProxy->mLock); michael@0: if (mProxy->mLastEvent == this) michael@0: mProxy->mLastEvent = nullptr; michael@0: } michael@0: michael@0: mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress, michael@0: mProgressMax); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsRefPtr mProxy; michael@0: michael@0: // parameters to OnTransportStatus michael@0: nsCOMPtr mTransport; michael@0: nsresult mStatus; michael@0: uint64_t mProgress; michael@0: uint64_t mProgressMax; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink) michael@0: michael@0: NS_IMETHODIMP michael@0: nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport, michael@0: nsresult status, michael@0: uint64_t progress, michael@0: uint64_t progressMax) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: nsRefPtr event; michael@0: { michael@0: MutexAutoLock lock(mLock); michael@0: michael@0: // try to coalesce events! ;-) michael@0: if (mLastEvent && (mCoalesceAll || mLastEvent->mStatus == status)) { michael@0: mLastEvent->mStatus = status; michael@0: mLastEvent->mProgress = progress; michael@0: mLastEvent->mProgressMax = progressMax; michael@0: } michael@0: else { michael@0: event = new nsTransportStatusEvent(this, transport, status, michael@0: progress, progressMax); michael@0: if (!event) michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: mLastEvent = event; // weak ref michael@0: } michael@0: } michael@0: if (event) { michael@0: rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("unable to post transport status event"); michael@0: michael@0: MutexAutoLock lock(mLock); // cleanup.. don't reference anymore! michael@0: mLastEvent = nullptr; michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: nsresult michael@0: net_NewTransportEventSinkProxy(nsITransportEventSink **result, michael@0: nsITransportEventSink *sink, michael@0: nsIEventTarget *target, michael@0: bool coalesceAll) michael@0: { michael@0: *result = new nsTransportEventSinkProxy(sink, target, coalesceAll); michael@0: if (!*result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(*result); michael@0: return NS_OK; michael@0: }