391 lines
13 KiB
C++
391 lines
13 KiB
C++
/**
|
|
* @file aihttpview.cpp
|
|
* @brief Definition of class AIHTTPView.
|
|
*
|
|
* Copyright (c) 2013, Aleric Inglewood.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution.
|
|
*
|
|
* CHANGELOG
|
|
* and additional copyright holders.
|
|
*
|
|
* 28/05/2013
|
|
* Initial version, written by Aleric Inglewood @ SL
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
#include "aihttpview.h"
|
|
#include "llrect.h"
|
|
#include "llerror.h"
|
|
#include "aicurlperservice.h"
|
|
#include "llviewerstats.h"
|
|
#include "llfontgl.h"
|
|
#include "aihttptimeout.h"
|
|
|
|
AIHTTPView* gHttpView = NULL;
|
|
static S32 sLineHeight;
|
|
|
|
// Forward declaration.
|
|
namespace AICurlInterface {
|
|
size_t getHTTPBandwidth(void);
|
|
U32 getNumHTTPAdded(void);
|
|
U32 getMaxHTTPAdded(void);
|
|
} // namespace AICurlInterface
|
|
|
|
//=============================================================================
|
|
|
|
//PerService_crat per_service_r(*service.second);
|
|
class AIServiceBar : public LLView
|
|
{
|
|
private:
|
|
AIHTTPView* mHTTPView;
|
|
std::string mName;
|
|
AIPerServicePtr mPerService;
|
|
|
|
public:
|
|
AIServiceBar(AIHTTPView* httpview, AIPerService::instance_map_type::value_type const& service)
|
|
: LLView("aiservice bar", LLRect(), FALSE), mHTTPView(httpview), mName(service.first), mPerService(service.second) { }
|
|
|
|
/*virtual*/ void draw(void);
|
|
/*virtual*/ LLRect getRequiredRect(void);
|
|
};
|
|
|
|
int const mc_col = number_of_capability_types; // Maximum connections column.
|
|
int const bw_col = number_of_capability_types + 1; // Bandwidth column.
|
|
|
|
void AIServiceBar::draw()
|
|
{
|
|
LLColor4 text_color = LLColor4::white;
|
|
F32 height = getRect().getHeight();
|
|
U32 start = 4;
|
|
LLFontGL::getFontMonospace()->renderUTF8(mName, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(mName);
|
|
std::string text;
|
|
AIPerService::CapabilityType* cts;
|
|
U32 is_used;
|
|
U32 is_inuse;
|
|
int total_added;
|
|
int event_polls;
|
|
int established_connections;
|
|
int concurrent_connections;
|
|
size_t bandwidth;
|
|
{
|
|
PerService_rat per_service_r(*mPerService);
|
|
is_used = per_service_r->is_used();
|
|
is_inuse = per_service_r->is_inuse();
|
|
total_added = per_service_r->mTotalAdded;
|
|
event_polls = per_service_r->mEventPolls;
|
|
established_connections = per_service_r->mEstablishedConnections;
|
|
concurrent_connections = per_service_r->mConcurrentConnections;
|
|
bandwidth = per_service_r->bandwidth().truncateData(AIHTTPView::getTime_40ms());
|
|
cts = per_service_r->mCapabilityType; // Not thread-safe, but we're only reading from it and only using the results to show in a debug console.
|
|
}
|
|
for (int col = 0; col < number_of_capability_types; ++col)
|
|
{
|
|
AICapabilityType capability_type = static_cast<AICapabilityType>(col);
|
|
AIPerService::CapabilityType& ct(cts[capability_type]);
|
|
start = mHTTPView->updateColumn(col, start);
|
|
U32 mask = AIPerService::CT2mask(capability_type);
|
|
if (!(is_used & mask))
|
|
{
|
|
text = " | ";
|
|
}
|
|
else
|
|
{
|
|
if (col < 2)
|
|
{
|
|
text = llformat(" | %hu-%hd-%lu,{%hu/%hu,%u}/%u",
|
|
ct.mApprovedRequests, ct.mQueuedCommands, ct.mQueuedRequests.size(),
|
|
ct.mAdded, ct.mConcurrentConnections, ct.mDownloading,
|
|
ct.mMaxPipelinedRequests);
|
|
}
|
|
else
|
|
{
|
|
text = llformat(" | --%hd-%lu,{%hu/%hu,%u}",
|
|
ct.mQueuedCommands, ct.mQueuedRequests.size(),
|
|
ct.mAdded, ct.mConcurrentConnections, ct.mDownloading);
|
|
}
|
|
if (capability_type == cap_texture || capability_type == cap_mesh)
|
|
{
|
|
if (!(is_inuse & mask))
|
|
{
|
|
ct.mFlags |= AIPerService::ctf_grey;
|
|
}
|
|
else
|
|
{
|
|
bool show = true;
|
|
int progress_counter = (ct.mFlags & AIPerService::ctf_progress_mask) >> AIPerService::ctf_progress_shift;
|
|
if ((ct.mFlags & AIPerService::ctf_success))
|
|
{
|
|
show = !(ct.mFlags & AIPerService::ctf_grey);
|
|
ct.mFlags &= ~(AIPerService::ctf_success|AIPerService::ctf_grey|AIPerService::ctf_progress_mask);
|
|
progress_counter = (progress_counter + 1) % 8;
|
|
ct.mFlags |= progress_counter << AIPerService::ctf_progress_shift;
|
|
}
|
|
if (show)
|
|
{
|
|
static char const* progress_utf8[8] = { " \xe2\xac\x93", " \xe2\xac\x95", " \xe2\x97\xa7", " \xe2\x97\xa9", " \xe2\xac\x92", " \xe2\xac\x94", " \xe2\x97\xa8", " \xe2\x97\xaa" };
|
|
text += progress_utf8[progress_counter];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, ((is_inuse & mask) == 0) ? LLColor4::grey2 : text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
}
|
|
start = mHTTPView->updateColumn(mc_col, start);
|
|
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
|
|
text = llformat(" | %d,%d,%d/%d", total_added, event_polls, established_connections, concurrent_connections);
|
|
#else
|
|
text = llformat(" | %d/%d", total_added, concurrent_connections);
|
|
#endif
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
start = mHTTPView->updateColumn(bw_col, start);
|
|
size_t max_bandwidth = mHTTPView->mMaxBandwidthPerService;
|
|
text = " | ";
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
text = llformat("%lu", bandwidth / 125);
|
|
if (bandwidth == 0)
|
|
{
|
|
text_color = LLColor4::grey2;
|
|
}
|
|
LLColor4 color = (bandwidth > max_bandwidth) ? LLColor4::red : ((bandwidth > max_bandwidth * .75f) ? LLColor4::yellow : text_color);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
text = llformat("/%lu", max_bandwidth / 125);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
}
|
|
|
|
LLRect AIServiceBar::getRequiredRect(void)
|
|
{
|
|
LLRect rect;
|
|
rect.mTop = sLineHeight;
|
|
return rect;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
static int const number_of_header_lines = 2;
|
|
|
|
class AIGLHTTPHeaderBar : public LLView
|
|
{
|
|
public:
|
|
AIGLHTTPHeaderBar(std::string const& name, AIHTTPView* httpview) :
|
|
LLView(name, FALSE), mHTTPView(httpview)
|
|
{
|
|
sLineHeight = llround(LLFontGL::getFontMonospace()->getLineHeight());
|
|
setRect(LLRect(0, 0, 200, sLineHeight * number_of_header_lines));
|
|
}
|
|
|
|
/*virtual*/ void draw(void);
|
|
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
|
/*virtual*/ LLRect getRequiredRect(void);
|
|
|
|
private:
|
|
AIHTTPView* mHTTPView;
|
|
};
|
|
|
|
void AIGLHTTPHeaderBar::draw(void)
|
|
{
|
|
S32 const v_offset = -1; // Offset from the bottom. Move header one pixel down.
|
|
S32 const h_offset = 4;
|
|
|
|
LLGLSUIDefault gls_ui;
|
|
|
|
LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
|
|
std::string text;
|
|
|
|
// First header line.
|
|
F32 height = v_offset + sLineHeight * number_of_header_lines;
|
|
text = "HTTP console -- [approved]-commandQ-curlQ,{added/max,downloading}[/max][ completed]";
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, h_offset, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
text = " | Added/Max";
|
|
U32 start = mHTTPView->updateColumn(mc_col, 100);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
text = " | Tot/Max BW (kbit/s)";
|
|
start = mHTTPView->updateColumn(bw_col, start);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP);
|
|
mHTTPView->setWidth(start + LLFontGL::getFontMonospace()->getWidth(text) + h_offset);
|
|
|
|
// Second header line.
|
|
height -= sLineHeight;
|
|
start = h_offset;
|
|
text = "Service (host:port)";
|
|
// This must match AICapabilityType!
|
|
static char const* caption[number_of_capability_types] = {
|
|
" | Textures", " | Inventory", " | Mesh", " | Other"
|
|
};
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
for (int col = 0; col < number_of_capability_types; ++col)
|
|
{
|
|
start = mHTTPView->updateColumn(col, start);
|
|
text = caption[col];
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
}
|
|
start = mHTTPView->updateColumn(mc_col, start);
|
|
text = llformat(" | %u/%u", AICurlInterface::getNumHTTPAdded(), AICurlInterface::getMaxHTTPAdded());
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
|
|
// This bandwidth is averaged over 1 seconds (in bytes/s).
|
|
size_t const bandwidth = AICurlInterface::getHTTPBandwidth();
|
|
size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125();
|
|
mHTTPView->mMaxBandwidthPerService = max_bandwidth * AIPerService::throttleFraction();
|
|
LLColor4 color = (bandwidth > max_bandwidth) ? LLColor4::red : ((bandwidth > max_bandwidth * .75f) ? LLColor4::yellow : text_color);
|
|
color[VALPHA] = text_color[VALPHA];
|
|
start = mHTTPView->updateColumn(bw_col, start);
|
|
text = " | ";
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, LLColor4::green, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
text = llformat("%lu", bandwidth / 125);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
start += LLFontGL::getFontMonospace()->getWidth(text);
|
|
text = llformat("/%lu", max_bandwidth / 125);
|
|
LLFontGL::getFontMonospace()->renderUTF8(text, 0, start, height, text_color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
}
|
|
|
|
BOOL AIGLHTTPHeaderBar::handleMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LLRect AIGLHTTPHeaderBar::getRequiredRect()
|
|
{
|
|
LLRect rect;
|
|
rect.mTop = sLineHeight * number_of_header_lines;
|
|
return rect;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
AIHTTPView::AIHTTPView(AIHTTPView::Params const& p) :
|
|
LLContainerView(p), mGLHTTPHeaderBar(NULL), mWidth(200)
|
|
{
|
|
setVisible(FALSE);
|
|
setRectAlpha(0.5);
|
|
}
|
|
|
|
AIHTTPView::~AIHTTPView()
|
|
{
|
|
delete mGLHTTPHeaderBar;
|
|
mGLHTTPHeaderBar = NULL;
|
|
}
|
|
|
|
U32 AIHTTPView::updateColumn(U32 col, U32 start)
|
|
{
|
|
if (col > mStartColumn.size())
|
|
{
|
|
// This happens when AIGLHTTPHeaderBar::draw is called before AIServiceBar::draw, which
|
|
// happens when there are no services (visible) at the moment the HTTP console is opened.
|
|
return start;
|
|
}
|
|
if (col == mStartColumn.size())
|
|
{
|
|
mStartColumn.push_back(start);
|
|
}
|
|
else if (mStartColumn[col] < start)
|
|
{
|
|
mStartColumn[col] = start;
|
|
}
|
|
return mStartColumn[col];
|
|
}
|
|
|
|
// virtual
|
|
void AIHTTPView::setVisible(BOOL visible)
|
|
{
|
|
if (visible && visible != getVisible())
|
|
AIPerService::resetUsed();
|
|
LLContainerView::setVisible(visible);
|
|
}
|
|
|
|
U64 AIHTTPView::sTime_40ms;
|
|
|
|
struct KillView
|
|
{
|
|
void operator()(LLView* viewp)
|
|
{
|
|
viewp->getParent()->removeChild(viewp);
|
|
viewp->die();
|
|
}
|
|
};
|
|
|
|
struct CreateServiceBar
|
|
{
|
|
AIHTTPView* mHTTPView;
|
|
|
|
CreateServiceBar(AIHTTPView* httpview) : mHTTPView(httpview) { }
|
|
|
|
void operator()(AIPerService::instance_map_type::value_type const& service)
|
|
{
|
|
if (!PerService_rat(*service.second)->is_used())
|
|
return;
|
|
AIServiceBar* service_bar = new AIServiceBar(mHTTPView, service);
|
|
mHTTPView->addChild(service_bar);
|
|
mHTTPView->mServiceBars.push_back(service_bar);
|
|
}
|
|
};
|
|
|
|
void AIHTTPView::draw()
|
|
{
|
|
for_each(mServiceBars.begin(), mServiceBars.end(), KillView());
|
|
mServiceBars.clear();
|
|
|
|
if (mGLHTTPHeaderBar)
|
|
{
|
|
removeChild(mGLHTTPHeaderBar);
|
|
mGLHTTPHeaderBar->die();
|
|
}
|
|
|
|
CreateServiceBar functor(this);
|
|
AIPerService::copy_forEach(functor);
|
|
|
|
sTime_40ms = get_clock_count() * AICurlPrivate::curlthread::HTTPTimeout::sClockWidth_40ms;
|
|
|
|
mGLHTTPHeaderBar = new AIGLHTTPHeaderBar("gl httpheader bar", this);
|
|
addChild(mGLHTTPHeaderBar);
|
|
|
|
reshape(mWidth, getRect().getHeight(), TRUE);
|
|
|
|
for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter)
|
|
{
|
|
LLView* viewp = *child_iter;
|
|
if (viewp->getRect().mBottom < 0)
|
|
{
|
|
viewp->setVisible(FALSE);
|
|
}
|
|
}
|
|
|
|
LLContainerView::draw();
|
|
}
|
|
|
|
BOOL AIHTTPView::handleMouseUp(S32 x, S32 y, MASK mask)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL AIHTTPView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|