Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca5f66da9f | ||
|
|
92d053d850 | ||
|
|
001ae80723 | ||
|
|
58d9a6d0b5 | ||
|
|
261316cb45 | ||
|
|
2ad4d2e672 | ||
|
|
1d9fa929fa | ||
|
|
26bb6236a0 | ||
|
|
b2acf5a623 | ||
|
|
bea88bb3a9 | ||
|
|
def2af2bdd | ||
|
|
6f6d705f22 | ||
|
|
e9c33104d3 | ||
|
|
985897f8ba | ||
|
|
4251b28e88 | ||
|
|
76540a211c | ||
|
|
904fc5a7dd | ||
|
|
4aebc159d5 | ||
|
|
f89227fc1a | ||
|
|
f50f383cc0 | ||
|
|
706ab387de | ||
|
|
cddfdb7d1d | ||
|
|
3c64578848 | ||
|
|
e1fe9b45e0 | ||
|
|
8fdc1d306f | ||
|
|
6e0c39bb68 | ||
|
|
f20b416cfe | ||
|
|
47e06b5216 | ||
|
|
bfcdf22705 | ||
|
|
d0db407faa | ||
|
|
d95b1c0441 | ||
|
|
837ba86d57 | ||
|
|
0cb1b463e1 |
+1
-1
@@ -1 +1 @@
|
|||||||
2020.3.2
|
2020.3.6
|
||||||
|
|||||||
@@ -691,6 +691,10 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_sampling_dirty = true;
|
_sampling_dirty = true;
|
||||||
}
|
}
|
||||||
|
else if( name == "anisotropy" )
|
||||||
|
{
|
||||||
|
_texture.setMaxAnisotropy( node->getFloatValue() );
|
||||||
|
}
|
||||||
else if( name == "additive-blend" )
|
else if( name == "additive-blend" )
|
||||||
{
|
{
|
||||||
_texture.useAdditiveBlend( node->getBoolValue() );
|
_texture.useAdditiveBlend( node->getBoolValue() );
|
||||||
|
|||||||
@@ -202,6 +202,12 @@ namespace canvas
|
|||||||
updateSampling();
|
updateSampling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void ODGauge::setMaxAnisotropy(float anis)
|
||||||
|
{
|
||||||
|
texture->setMaxAnisotropy(anis);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ODGauge::setRender(bool render)
|
void ODGauge::setRender(bool render)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ namespace canvas
|
|||||||
int coverage_samples = 0,
|
int coverage_samples = 0,
|
||||||
int color_samples = 0 );
|
int color_samples = 0 );
|
||||||
|
|
||||||
|
void setMaxAnisotropy(float anis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable/Disable updating the texture (If disabled the contents of the
|
* Enable/Disable updating the texture (If disabled the contents of the
|
||||||
* texture remains with the outcome of the last rendering pass)
|
* texture remains with the outcome of the last rendering pass)
|
||||||
|
|||||||
@@ -218,6 +218,9 @@ const float SG_RADIANS_TO_DEGREES = 180.0f / SG_PI;
|
|||||||
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
||||||
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
||||||
|
|
||||||
|
/** Minimum expiry time of PagedLOD within the Tile. Overridden by /sim/rendering/plod-minimum-expiry-time-secs **/
|
||||||
|
#define SG_TILE_MIN_EXPIRY 180.0
|
||||||
|
|
||||||
/** Radius of scenery tiles in m **/
|
/** Radius of scenery tiles in m **/
|
||||||
#define SG_TILE_RADIUS 14000.0
|
#define SG_TILE_RADIUS 14000.0
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ include (SimGearComponent)
|
|||||||
|
|
||||||
set(HEADERS debug_types.h
|
set(HEADERS debug_types.h
|
||||||
logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx
|
logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx
|
||||||
LogCallback.hxx LogEntry.hxx)
|
LogCallback.hxx LogEntry.hxx
|
||||||
|
ErrorReportingCallback.hxx)
|
||||||
|
|
||||||
set(SOURCES logstream.cxx BufferedLogCallback.cxx
|
set(SOURCES logstream.cxx BufferedLogCallback.cxx
|
||||||
LogCallback.cxx LogEntry.cxx)
|
LogCallback.cxx LogEntry.cxx
|
||||||
|
ErrorReportingCallback.cxx
|
||||||
|
)
|
||||||
|
|
||||||
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <simgear_config.h>
|
||||||
|
|
||||||
|
#include "ErrorReportingCallback.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
static ErrorReportCallback static_callback;
|
||||||
|
|
||||||
|
void setErrorReportCallback(ErrorReportCallback cb)
|
||||||
|
{
|
||||||
|
static_callback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reportError(const std::string& msg, const std::string& more)
|
||||||
|
{
|
||||||
|
if (!static_callback)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_callback(msg, more, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportFatalError(const std::string& msg, const std::string& more)
|
||||||
|
{
|
||||||
|
if (!static_callback)
|
||||||
|
return;
|
||||||
|
static_callback(msg, more, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace simgear
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
void reportError(const std::string& msg, const std::string& more = {});
|
||||||
|
|
||||||
|
void reportFatalError(const std::string& msg, const std::string& more = {});
|
||||||
|
|
||||||
|
using ErrorReportCallback = std::function<void(const std::string& msg, const std::string& more, bool isFatal)>;
|
||||||
|
|
||||||
|
void setErrorReportCallback(ErrorReportCallback cb);
|
||||||
|
|
||||||
|
} // namespace simgear
|
||||||
@@ -45,14 +45,6 @@ namespace simgear
|
|||||||
std::atomic<int> receiveDepth;
|
std::atomic<int> receiveDepth;
|
||||||
std::atomic<int> sentMessageCount;
|
std::atomic<int> sentMessageCount;
|
||||||
|
|
||||||
void UnlockList()
|
|
||||||
{
|
|
||||||
_lock.unlock();
|
|
||||||
}
|
|
||||||
void LockList()
|
|
||||||
{
|
|
||||||
_lock.lock();
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
Transmitter() : receiveDepth(0), sentMessageCount(0)
|
Transmitter() : receiveDepth(0), sentMessageCount(0)
|
||||||
{
|
{
|
||||||
@@ -69,20 +61,17 @@ namespace simgear
|
|||||||
// most recently registered recipients should process the messages/events first.
|
// most recently registered recipients should process the messages/events first.
|
||||||
virtual void Register(IReceiver& r)
|
virtual void Register(IReceiver& r)
|
||||||
{
|
{
|
||||||
LockList();
|
std::lock_guard<std::mutex> scopeLock(_lock);
|
||||||
recipient_list.push_back(&r);
|
recipient_list.push_back(&r);
|
||||||
r.OnRegisteredAtTransmitter(this);
|
r.OnRegisteredAtTransmitter(this);
|
||||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
|
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
|
||||||
deleted_recipients.remove(&r);
|
deleted_recipients.remove(&r);
|
||||||
|
|
||||||
UnlockList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes an object from receving message from this transmitter
|
// Removes an object from receving message from this transmitter
|
||||||
virtual void DeRegister(IReceiver& R)
|
virtual void DeRegister(IReceiver& R)
|
||||||
{
|
{
|
||||||
LockList();
|
std::lock_guard<std::mutex> scopeLock(_lock);
|
||||||
//printf("Remove %x\n", &R);
|
|
||||||
if (recipient_list.size())
|
if (recipient_list.size())
|
||||||
{
|
{
|
||||||
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
|
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
|
||||||
@@ -93,7 +82,6 @@ namespace simgear
|
|||||||
deleted_recipients.push_back(&R);
|
deleted_recipients.push_back(&R);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UnlockList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
|
||||||
@@ -107,69 +95,68 @@ namespace simgear
|
|||||||
ReceiptStatus return_status = ReceiptStatusNotProcessed;
|
ReceiptStatus return_status = ReceiptStatusNotProcessed;
|
||||||
|
|
||||||
sentMessageCount++;
|
sentMessageCount++;
|
||||||
try
|
|
||||||
|
std::vector<IReceiver*> temp;
|
||||||
{
|
{
|
||||||
LockList();
|
std::lock_guard<std::mutex> scopeLock(_lock);
|
||||||
if (receiveDepth == 0)
|
if (receiveDepth == 0)
|
||||||
deleted_recipients.clear();
|
deleted_recipients.clear();
|
||||||
receiveDepth++;
|
receiveDepth++;
|
||||||
std::vector<IReceiver*> temp(recipient_list.size());
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
|
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
|
||||||
{
|
{
|
||||||
temp[idx++] = *i;
|
temp.push_back(*i);
|
||||||
}
|
}
|
||||||
UnlockList();
|
}
|
||||||
int tempSize = temp.size();
|
int tempSize = temp.size();
|
||||||
for (int index = 0; index < tempSize; index++)
|
for (int index = 0; index < tempSize; index++)
|
||||||
|
{
|
||||||
|
IReceiver* R = temp[index];
|
||||||
{
|
{
|
||||||
IReceiver* R = temp[index];
|
std::lock_guard<std::mutex> scopeLock(_lock);
|
||||||
LockList();
|
|
||||||
if (deleted_recipients.size())
|
if (deleted_recipients.size())
|
||||||
{
|
{
|
||||||
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
|
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
|
||||||
{
|
{
|
||||||
UnlockList();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UnlockList();
|
|
||||||
if (R)
|
|
||||||
{
|
|
||||||
ReceiptStatus rstat = R->Receive(M);
|
|
||||||
switch (rstat)
|
|
||||||
{
|
|
||||||
case ReceiptStatusFail:
|
|
||||||
return_status = ReceiptStatusFail;
|
|
||||||
break;
|
|
||||||
case ReceiptStatusPending:
|
|
||||||
return_status = ReceiptStatusPending;
|
|
||||||
break;
|
|
||||||
case ReceiptStatusPendingFinished:
|
|
||||||
return rstat;
|
|
||||||
|
|
||||||
case ReceiptStatusNotProcessed:
|
|
||||||
break;
|
|
||||||
case ReceiptStatusOK:
|
|
||||||
if (return_status == ReceiptStatusNotProcessed)
|
|
||||||
return_status = rstat;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ReceiptStatusAbort:
|
|
||||||
return ReceiptStatusAbort;
|
|
||||||
|
|
||||||
case ReceiptStatusFinished:
|
|
||||||
return ReceiptStatusOK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (R)
|
||||||
|
{
|
||||||
|
ReceiptStatus rstat = R->Receive(M);
|
||||||
|
switch (rstat)
|
||||||
|
{
|
||||||
|
case ReceiptStatusFail:
|
||||||
|
return_status = ReceiptStatusFail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReceiptStatusPending:
|
||||||
|
return_status = ReceiptStatusPending;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReceiptStatusPendingFinished:
|
||||||
|
return rstat;
|
||||||
|
|
||||||
|
case ReceiptStatusNotProcessed:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReceiptStatusOK:
|
||||||
|
if (return_status == ReceiptStatusNotProcessed)
|
||||||
|
return_status = rstat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReceiptStatusAbort:
|
||||||
|
return ReceiptStatusAbort;
|
||||||
|
|
||||||
|
case ReceiptStatusFinished:
|
||||||
|
return ReceiptStatusOK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
// return_status = ReceiptStatusAbort;
|
|
||||||
}
|
|
||||||
receiveDepth--;
|
receiveDepth--;
|
||||||
return return_status;
|
return return_status;
|
||||||
}
|
}
|
||||||
@@ -177,9 +164,8 @@ namespace simgear
|
|||||||
// number of currently registered recipients
|
// number of currently registered recipients
|
||||||
virtual int Count()
|
virtual int Count()
|
||||||
{
|
{
|
||||||
LockList();
|
std::lock_guard<std::mutex> scopeLock(_lock);
|
||||||
return recipient_list.size();
|
return recipient_list.size();
|
||||||
UnlockList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// number of sent messages.
|
// number of sent messages.
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
#include "metar.hxx"
|
#include "metar.hxx"
|
||||||
@@ -646,16 +647,21 @@ bool SGMetar::scanWind()
|
|||||||
double gust = NaN;
|
double gust = NaN;
|
||||||
if (*m == 'G') {
|
if (*m == 'G') {
|
||||||
m++;
|
m++;
|
||||||
if (!scanNumber(&m, &i, 2, 3))
|
if (!strncmp(m, "//", 2)) // speed not measurable
|
||||||
|
m += 2, i = -1;
|
||||||
|
else if (!scanNumber(&m, &i, 2, 3))
|
||||||
return false;
|
return false;
|
||||||
gust = i;
|
|
||||||
|
if (i != -1)
|
||||||
|
gust = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
double factor;
|
double factor;
|
||||||
if (!strncmp(m, "KT", 2))
|
if (!strncmp(m, "KT", 2))
|
||||||
m += 2, factor = SG_KT_TO_MPS;
|
m += 2, factor = SG_KT_TO_MPS;
|
||||||
else if (!strncmp(m, "KMH", 3))
|
else if (!strncmp(m, "KMH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "KPH", 3)) // ??
|
else if (!strncmp(m, "KPH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "MPS", 3))
|
else if (!strncmp(m, "MPS", 3))
|
||||||
m += 3, factor = 1.0;
|
m += 3, factor = 1.0;
|
||||||
@@ -680,18 +686,28 @@ bool SGMetar::scanVariability()
|
|||||||
{
|
{
|
||||||
char *m = _m;
|
char *m = _m;
|
||||||
int from, to;
|
int from, to;
|
||||||
if (!scanNumber(&m, &from, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, from = -1;
|
||||||
|
else if (!scanNumber(&m, &from, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*m++ != 'V')
|
if (*m++ != 'V')
|
||||||
return false;
|
return false;
|
||||||
if (!scanNumber(&m, &to, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, to = -1;
|
||||||
|
else if (!scanNumber(&m, &to, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!scanBoundary(&m))
|
if (!scanBoundary(&m))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_m = m;
|
_m = m;
|
||||||
_wind_range_from = from;
|
_wind_range_from = from;
|
||||||
_wind_range_to = to;
|
_wind_range_to = to;
|
||||||
_grpcount++;
|
_grpcount++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,9 +1069,12 @@ bool SGMetar::scanSkyCondition()
|
|||||||
return false;
|
return false;
|
||||||
m += i;
|
m += i;
|
||||||
|
|
||||||
if (!strncmp(m, "///", 3)) // vis not measurable (e.g. because of heavy snowing)
|
if (!strncmp(m, "///", 3)) { // vis not measurable (e.g. because of heavy snowing)
|
||||||
m += 3, i = -1;
|
m += 3, i = -1;
|
||||||
else if (scanBoundary(&m)) {
|
sg_srandom_time();
|
||||||
|
// randomize the base height to avoid the black sky issue
|
||||||
|
i = 50 + static_cast<int>(sg_random() * 250.0); // range [5,000, 30,000]
|
||||||
|
} else if (scanBoundary(&m)) {
|
||||||
_m = m;
|
_m = m;
|
||||||
return true; // ignore single OVC/BKN/...
|
return true; // ignore single OVC/BKN/...
|
||||||
} else if (!scanNumber(&m, &i, 3))
|
} else if (!scanNumber(&m, &i, 3))
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ void test_sensor_failure_wind()
|
|||||||
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
||||||
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
||||||
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m2("2020/10/21 16:55 LIVD 211655Z /////KT CAVOK 07/03 Q1023 RMK SKC VIS MIN 9999 BLU");
|
||||||
|
SG_CHECK_EQUAL(m2.getWindDir(), -1);
|
||||||
|
SG_CHECK_EQUAL_EP2(m2.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m3("2020/11/17 16:00 CYAZ 171600Z 14040G//KT 10SM -RA OVC012 12/11 A2895 RMK NS8 VIA CYXY SLP806 DENSITY ALT 900FT");
|
||||||
|
SG_CHECK_EQUAL(m3.getWindDir(), 140);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getWindSpeed_kt(), 40, TEST_EPSILON);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getGustSpeed_kt(), SGMetarNaN, TEST_EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_wind_unit_not_specified()
|
void test_wind_unit_not_specified()
|
||||||
|
|||||||
+85
-47
@@ -61,6 +61,10 @@ public:
|
|||||||
|
|
||||||
struct dns_ctx * ctx;
|
struct dns_ctx * ctx;
|
||||||
static size_t instanceCounter;
|
static size_t instanceCounter;
|
||||||
|
|
||||||
|
using RequestVec = std::vector<Request_ptr>;
|
||||||
|
|
||||||
|
RequestVec _activeRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t Client::ClientPrivate::instanceCounter = 0;
|
size_t Client::ClientPrivate::instanceCounter = 0;
|
||||||
@@ -78,6 +82,11 @@ Request::~Request()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Request::cancel()
|
||||||
|
{
|
||||||
|
_cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Request::isTimeout() const
|
bool Request::isTimeout() const
|
||||||
{
|
{
|
||||||
return (time(NULL) - _start) > _timeout_secs;
|
return (time(NULL) - _start) > _timeout_secs;
|
||||||
@@ -114,18 +123,20 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
|
|||||||
{
|
{
|
||||||
SRVRequest * r = static_cast<SRVRequest*>(data);
|
SRVRequest * r = static_cast<SRVRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnssrv_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnssrv_qname;
|
r->cname = result->dnssrv_cname;
|
||||||
r->ttl = result->dnssrv_ttl;
|
r->qname = result->dnssrv_qname;
|
||||||
for (int i = 0; i < result->dnssrv_nrr; i++) {
|
r->ttl = result->dnssrv_ttl;
|
||||||
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
|
for (int i = 0; i < result->dnssrv_nrr; i++) {
|
||||||
r->entries.push_back(srv);
|
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
|
||||||
srv->priority = result->dnssrv_srv[i].priority;
|
r->entries.push_back(srv);
|
||||||
srv->weight = result->dnssrv_srv[i].weight;
|
srv->priority = result->dnssrv_srv[i].priority;
|
||||||
srv->port = result->dnssrv_srv[i].port;
|
srv->weight = result->dnssrv_srv[i].weight;
|
||||||
srv->target = result->dnssrv_srv[i].name;
|
srv->port = result->dnssrv_srv[i].port;
|
||||||
|
srv->target = result->dnssrv_srv[i].name;
|
||||||
|
}
|
||||||
|
std::sort(r->entries.begin(), r->entries.end(), sortSRV);
|
||||||
}
|
}
|
||||||
std::sort( r->entries.begin(), r->entries.end(), sortSRV );
|
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
r->setComplete();
|
r->setComplete();
|
||||||
@@ -134,11 +145,16 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
|
|||||||
void SRVRequest::submit( Client * client )
|
void SRVRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
// if service is defined, pass service and protocol
|
// if service is defined, pass service and protocol
|
||||||
if (!dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), _service.empty() ? NULL : _protocol.c_str(), 0, dnscbSRV, this )) {
|
auto q = dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(),
|
||||||
|
_service.empty() ? NULL : _protocol.c_str(),
|
||||||
|
0, dnscbSRV, this);
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
TXTRequest::TXTRequest( const std::string & dn ) :
|
TXTRequest::TXTRequest( const std::string & dn ) :
|
||||||
@@ -151,22 +167,24 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
|
|||||||
{
|
{
|
||||||
TXTRequest * r = static_cast<TXTRequest*>(data);
|
TXTRequest * r = static_cast<TXTRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnstxt_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnstxt_qname;
|
r->cname = result->dnstxt_cname;
|
||||||
r->ttl = result->dnstxt_ttl;
|
r->qname = result->dnstxt_qname;
|
||||||
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
r->ttl = result->dnstxt_ttl;
|
||||||
//TODO: interprete the .len field of dnstxt_txt?
|
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
||||||
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
|
//TODO: interprete the .len field of dnstxt_txt?
|
||||||
if (!rawTxt) {
|
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
|
||||||
continue;
|
if (!rawTxt) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const string txt{rawTxt};
|
const string txt{rawTxt};
|
||||||
r->entries.push_back(txt);
|
r->entries.push_back(txt);
|
||||||
string_list tokens = simgear::strutils::split( txt, "=", 1 );
|
string_list tokens = simgear::strutils::split(txt, "=", 1);
|
||||||
if( tokens.size() == 2 ) {
|
if (tokens.size() == 2) {
|
||||||
r->attributes[tokens[0]] = tokens[1];
|
r->attributes[tokens[0]] = tokens[1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
@@ -176,11 +194,13 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
|
|||||||
void TXTRequest::submit( Client * client )
|
void TXTRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
// protocol and service an already encoded in DN so pass in NULL for both
|
// protocol and service an already encoded in DN so pass in NULL for both
|
||||||
if (!dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this )) {
|
auto q = dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this);
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -195,27 +215,29 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
|
|||||||
{
|
{
|
||||||
NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
|
NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnsnaptr_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnsnaptr_qname;
|
r->cname = result->dnsnaptr_cname;
|
||||||
r->ttl = result->dnsnaptr_ttl;
|
r->qname = result->dnsnaptr_qname;
|
||||||
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
|
r->ttl = result->dnsnaptr_ttl;
|
||||||
if( !r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service )
|
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
|
||||||
continue;
|
if (!r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service)
|
||||||
|
continue;
|
||||||
|
|
||||||
//TODO: case ignore and result flags may have more than one flag
|
//TODO: case ignore and result flags may have more than one flag
|
||||||
if( !r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags )
|
if (!r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
|
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
|
||||||
r->entries.push_back(naptr);
|
r->entries.push_back(naptr);
|
||||||
naptr->order = result->dnsnaptr_naptr[i].order;
|
naptr->order = result->dnsnaptr_naptr[i].order;
|
||||||
naptr->preference = result->dnsnaptr_naptr[i].preference;
|
naptr->preference = result->dnsnaptr_naptr[i].preference;
|
||||||
naptr->flags = result->dnsnaptr_naptr[i].flags;
|
naptr->flags = result->dnsnaptr_naptr[i].flags;
|
||||||
naptr->service = result->dnsnaptr_naptr[i].service;
|
naptr->service = result->dnsnaptr_naptr[i].service;
|
||||||
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
|
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
|
||||||
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
|
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
|
||||||
|
}
|
||||||
|
std::sort(r->entries.begin(), r->entries.end(), sortNAPTR);
|
||||||
}
|
}
|
||||||
std::sort( r->entries.begin(), r->entries.end(), sortNAPTR );
|
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
r->setComplete();
|
r->setComplete();
|
||||||
@@ -223,11 +245,13 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
|
|||||||
|
|
||||||
void NAPTRRequest::submit( Client * client )
|
void NAPTRRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
if (!dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this )) {
|
auto q = dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this);
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -242,6 +266,7 @@ Client::Client() :
|
|||||||
|
|
||||||
void Client::makeRequest(const Request_ptr& r)
|
void Client::makeRequest(const Request_ptr& r)
|
||||||
{
|
{
|
||||||
|
d->_activeRequests.push_back(r);
|
||||||
r->submit(this);
|
r->submit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +277,19 @@ void Client::update(int waitTimeout)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
dns_ioevent(d->ctx, now);
|
dns_ioevent(d->ctx, now);
|
||||||
|
|
||||||
|
// drop our owning ref to completed requests,
|
||||||
|
// and cancel any which timed out
|
||||||
|
auto it = std::remove_if(d->_activeRequests.begin(), d->_activeRequests.end(),
|
||||||
|
[this](const Request_ptr& r) {
|
||||||
|
if (r->isTimeout()) {
|
||||||
|
dns_cancel(d->ctx, reinterpret_cast<struct dns_query*>(r->_query));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r->isComplete();
|
||||||
|
});
|
||||||
|
d->_activeRequests.erase(it, d->_activeRequests.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace DNS
|
} // of namespace DNS
|
||||||
|
|||||||
@@ -40,28 +40,38 @@ namespace DNS
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
|
using UDNSQueryPtr = void*;
|
||||||
|
|
||||||
class Request : public SGReferenced
|
class Request : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Request( const std::string & dn );
|
Request( const std::string & dn );
|
||||||
virtual ~Request();
|
virtual ~Request();
|
||||||
std::string getDn() const { return _dn; }
|
const std::string& getDn() const { return _dn; }
|
||||||
int getType() const { return _type; }
|
int getType() const { return _type; }
|
||||||
bool isComplete() const { return _complete; }
|
bool isComplete() const { return _complete; }
|
||||||
bool isTimeout() const;
|
bool isTimeout() const;
|
||||||
void setComplete( bool b = true ) { _complete = b; }
|
void setComplete( bool b = true ) { _complete = b; }
|
||||||
|
bool isCancelled() const { return _cancelled; }
|
||||||
|
|
||||||
virtual void submit( Client * client) = 0;
|
virtual void submit( Client * client) = 0;
|
||||||
|
|
||||||
|
void cancel();
|
||||||
|
|
||||||
std::string cname;
|
std::string cname;
|
||||||
std::string qname;
|
std::string qname;
|
||||||
unsigned ttl;
|
unsigned ttl;
|
||||||
protected:
|
protected:
|
||||||
|
friend class Client;
|
||||||
|
|
||||||
|
UDNSQueryPtr _query = nullptr;
|
||||||
std::string _dn;
|
std::string _dn;
|
||||||
int _type;
|
int _type;
|
||||||
bool _complete;
|
bool _complete;
|
||||||
time_t _timeout_secs;
|
time_t _timeout_secs;
|
||||||
time_t _start;
|
time_t _start;
|
||||||
|
bool _cancelled = false;
|
||||||
};
|
};
|
||||||
typedef SGSharedPtr<Request> Request_ptr;
|
typedef SGSharedPtr<Request> Request_ptr;
|
||||||
|
|
||||||
@@ -69,7 +79,7 @@ class NAPTRRequest : public Request
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NAPTRRequest( const std::string & dn );
|
NAPTRRequest( const std::string & dn );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
struct NAPTR : SGReferenced {
|
struct NAPTR : SGReferenced {
|
||||||
int order;
|
int order;
|
||||||
@@ -92,7 +102,7 @@ class SRVRequest : public Request
|
|||||||
public:
|
public:
|
||||||
SRVRequest( const std::string & dn );
|
SRVRequest( const std::string & dn );
|
||||||
SRVRequest( const std::string & dn, const string & service, const string & protocol );
|
SRVRequest( const std::string & dn, const string & service, const string & protocol );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
struct SRV : SGReferenced {
|
struct SRV : SGReferenced {
|
||||||
int priority;
|
int priority;
|
||||||
@@ -112,7 +122,7 @@ class TXTRequest : public Request
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TXTRequest( const std::string & dn );
|
TXTRequest( const std::string & dn );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
typedef std::vector<string> TXT_list;
|
typedef std::vector<string> TXT_list;
|
||||||
typedef std::map<std::string,std::string> TXT_Attribute_map;
|
typedef std::map<std::string,std::string> TXT_Attribute_map;
|
||||||
|
|||||||
@@ -437,32 +437,37 @@ public:
|
|||||||
|
|
||||||
ArchiveExtractTask(const ArchiveExtractTask &) = delete;
|
ArchiveExtractTask(const ArchiveExtractTask &) = delete;
|
||||||
|
|
||||||
HTTPRepoPrivate::ProcessResult run(HTTPRepoPrivate *repo) {
|
HTTPRepoPrivate::ProcessResult run(HTTPRepoPrivate* repo)
|
||||||
size_t rd = file.read((char *)buffer, bufferSize);
|
{
|
||||||
extractor.extractBytes(buffer, rd);
|
if (!buffer) {
|
||||||
|
return HTTPRepoPrivate::ProcessFailed;
|
||||||
if (file.eof()) {
|
|
||||||
extractor.flush();
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
if (!extractor.isAtEndOfArchive()) {
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << relativePath);
|
|
||||||
repo->failedToUpdateChild(relativePath,
|
|
||||||
HTTPRepository::REPO_ERROR_IO);
|
|
||||||
return HTTPRepoPrivate::ProcessFailed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extractor.hasError()) {
|
size_t rd = file.read((char*)buffer, bufferSize);
|
||||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << relativePath);
|
extractor.extractBytes(buffer, rd);
|
||||||
repo->failedToUpdateChild(relativePath,
|
|
||||||
HTTPRepository::REPO_ERROR_IO);
|
if (file.eof()) {
|
||||||
return HTTPRepoPrivate::ProcessFailed;
|
extractor.flush();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (!extractor.isAtEndOfArchive()) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << relativePath);
|
||||||
|
repo->failedToUpdateChild(relativePath,
|
||||||
|
HTTPRepository::REPO_ERROR_IO);
|
||||||
|
return HTTPRepoPrivate::ProcessFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extractor.hasError()) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << relativePath);
|
||||||
|
repo->failedToUpdateChild(relativePath,
|
||||||
|
HTTPRepository::REPO_ERROR_IO);
|
||||||
|
return HTTPRepoPrivate::ProcessFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HTTPRepoPrivate::ProcessDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTPRepoPrivate::ProcessDone;
|
return HTTPRepoPrivate::ProcessContinue;
|
||||||
}
|
|
||||||
|
|
||||||
return HTTPRepoPrivate::ProcessContinue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ArchiveExtractTask() { free(buffer); }
|
~ArchiveExtractTask() { free(buffer); }
|
||||||
@@ -976,49 +981,71 @@ HTTPRepository::failure() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void gotBodyData(const char *s, int n) override {
|
void gotBodyData(const char* s, int n) override
|
||||||
if (!file.get()) {
|
{
|
||||||
file.reset(new SGBinaryFile(pathInRepo));
|
if (!file.get()) {
|
||||||
if (!file->open(SG_IO_OUT)) {
|
const bool ok = createOutputFile();
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN,
|
if (!ok) {
|
||||||
"unable to create file " << pathInRepo);
|
_directory->repository()->http->cancelRequest(
|
||||||
_directory->repository()->http->cancelRequest(
|
this, "Unable to create output file:" + pathInRepo.utf8Str());
|
||||||
this, "Unable to create output file:" + pathInRepo.utf8Str());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_init(&hashContext);
|
sha1_write(&hashContext, s, n);
|
||||||
|
file->write(s, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_write(&hashContext, s, n);
|
bool createOutputFile()
|
||||||
file->write(s, n);
|
{
|
||||||
}
|
file.reset(new SGBinaryFile(pathInRepo));
|
||||||
|
if (!file->open(SG_IO_OUT)) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN,
|
||||||
|
"unable to create file " << pathInRepo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void onDone() override {
|
sha1_init(&hashContext);
|
||||||
file->close();
|
return true;
|
||||||
if (responseCode() == 200) {
|
|
||||||
std::string hash =
|
|
||||||
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
|
||||||
_directory->didUpdateFile(fileName, hash, contentSize());
|
|
||||||
} else if (responseCode() == 404) {
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN,
|
|
||||||
"terrasync file not found on server: "
|
|
||||||
<< fileName << " for " << _directory->absolutePath());
|
|
||||||
_directory->didFailToUpdateFile(
|
|
||||||
fileName, HTTPRepository::REPO_ERROR_FILE_NOT_FOUND);
|
|
||||||
} else {
|
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN,
|
|
||||||
"terrasync file download error on server: "
|
|
||||||
<< fileName << " for " << _directory->absolutePath()
|
|
||||||
<< "\n\tserver responded: " << responseCode() << "/"
|
|
||||||
<< responseReason());
|
|
||||||
_directory->didFailToUpdateFile(fileName,
|
|
||||||
HTTPRepository::REPO_ERROR_HTTP);
|
|
||||||
// should we every retry here?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_directory->repository()->finishedRequest(
|
void onDone() override
|
||||||
this, HTTPRepoPrivate::RequestFinish::Done);
|
{
|
||||||
}
|
const bool is200Response = (responseCode() == 200);
|
||||||
|
if (!file && is200Response) {
|
||||||
|
// if the server defines a zero-byte file, we will never call
|
||||||
|
// gotBodyData, so create the file here
|
||||||
|
// this ensures all the logic below works as expected
|
||||||
|
createOutputFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
file->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is200Response) {
|
||||||
|
std::string hash =
|
||||||
|
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
||||||
|
_directory->didUpdateFile(fileName, hash, contentSize());
|
||||||
|
} else if (responseCode() == 404) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN,
|
||||||
|
"terrasync file not found on server: "
|
||||||
|
<< fileName << " for " << _directory->absolutePath());
|
||||||
|
_directory->didFailToUpdateFile(
|
||||||
|
fileName, HTTPRepository::REPO_ERROR_FILE_NOT_FOUND);
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_WARN,
|
||||||
|
"terrasync file download error on server: "
|
||||||
|
<< fileName << " for " << _directory->absolutePath()
|
||||||
|
<< "\n\tserver responded: " << responseCode() << "/"
|
||||||
|
<< responseReason());
|
||||||
|
_directory->didFailToUpdateFile(fileName,
|
||||||
|
HTTPRepository::REPO_ERROR_HTTP);
|
||||||
|
// should we every retry here?
|
||||||
|
}
|
||||||
|
|
||||||
|
_directory->repository()->finishedRequest(
|
||||||
|
this, HTTPRepoPrivate::RequestFinish::Done);
|
||||||
|
}
|
||||||
|
|
||||||
void onFail() override {
|
void onFail() override {
|
||||||
HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;
|
HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;
|
||||||
|
|||||||
@@ -566,8 +566,10 @@ bool SGBinObject::read_bin( const SGPath& file ) {
|
|||||||
sgReadUInt( fp, &header );
|
sgReadUInt( fp, &header );
|
||||||
|
|
||||||
if (sgReadError()) {
|
if (sgReadError()) {
|
||||||
|
int code = 0;
|
||||||
|
const char* gzErrorString = gzerror(fp, &code);
|
||||||
gzclose(fp);
|
gzclose(fp);
|
||||||
throw sg_io_exception("Unable to read BTG header: " + simgear::strutils::error_string(errno), sg_location(file));
|
throw sg_io_exception("Unable to read BTG header: " + string{gzErrorString} + ", code =" + std::to_string(code), sg_location(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ((header & 0xFF000000) >> 24) == 'S' &&
|
if ( ((header & 0xFF000000) >> 24) == 'S' &&
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ using TestApi = simgear::HTTP::TestApi;
|
|||||||
|
|
||||||
std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
|
std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
|
||||||
{
|
{
|
||||||
|
if (name == "zeroByteFile") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
// random content but which definitely depends on our tree location
|
// random content but which definitely depends on our tree location
|
||||||
// and revision.
|
// and revision.
|
||||||
@@ -446,6 +450,7 @@ void testBasicClone(HTTP::Client* cl)
|
|||||||
verifyFileState(p, "fileA");
|
verifyFileState(p, "fileA");
|
||||||
verifyFileState(p, "dirA/subdirA/fileAAA");
|
verifyFileState(p, "dirA/subdirA/fileAAA");
|
||||||
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
|
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
|
||||||
|
verifyFileState(p, "dirA/subdirA/zeroByteFile");
|
||||||
|
|
||||||
global_repo->findEntry("fileA")->revision++;
|
global_repo->findEntry("fileA")->revision++;
|
||||||
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
|
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
|
||||||
@@ -911,6 +916,8 @@ int main(int argc, char* argv[])
|
|||||||
global_repo->defineFile("dirA/fileAC");
|
global_repo->defineFile("dirA/fileAC");
|
||||||
global_repo->defineFile("dirA/subdirA/fileAAA");
|
global_repo->defineFile("dirA/subdirA/fileAAA");
|
||||||
global_repo->defineFile("dirA/subdirA/fileAAB");
|
global_repo->defineFile("dirA/subdirA/fileAAB");
|
||||||
|
global_repo->defineFile("dirA/subdirA/zeroByteFile");
|
||||||
|
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAA");
|
global_repo->defineFile("dirB/subdirA/fileBAA");
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAB");
|
global_repo->defineFile("dirB/subdirA/fileBAB");
|
||||||
global_repo->defineFile("dirB/subdirA/fileBAC");
|
global_repo->defineFile("dirB/subdirA/fileBAC");
|
||||||
|
|||||||
+25
-23
@@ -511,32 +511,34 @@ public:
|
|||||||
const size_t BUFFER_SIZE = 1024 * 1024;
|
const size_t BUFFER_SIZE = 1024 * 1024;
|
||||||
void* buf = malloc(BUFFER_SIZE);
|
void* buf = malloc(BUFFER_SIZE);
|
||||||
|
|
||||||
try {
|
int result = unzGoToFirstFile(zip);
|
||||||
int result = unzGoToFirstFile(zip);
|
if (result != UNZ_OK) {
|
||||||
if (result != UNZ_OK) {
|
SG_LOG(SG_IO, SG_ALERT, outer->rootPath() << "failed to go to first file in archive:" << result);
|
||||||
throw sg_exception("failed to go to first file in archive");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
extractCurrentFile(zip, (char*)buf, BUFFER_SIZE);
|
|
||||||
if (state == FILTER_STOPPED) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = unzGoToNextFile(zip);
|
|
||||||
if (result == UNZ_END_OF_LIST_OF_FILE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (result != UNZ_OK) {
|
|
||||||
throw sg_io_exception("failed to go to next file in the archive");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state = END_OF_ARCHIVE;
|
|
||||||
}
|
|
||||||
catch (sg_exception&) {
|
|
||||||
state = BAD_ARCHIVE;
|
state = BAD_ARCHIVE;
|
||||||
|
free(buf);
|
||||||
|
unzClose(zip);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
extractCurrentFile(zip, (char*)buf, BUFFER_SIZE);
|
||||||
|
if (state == FILTER_STOPPED) {
|
||||||
|
state = END_OF_ARCHIVE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = unzGoToNextFile(zip);
|
||||||
|
if (result == UNZ_END_OF_LIST_OF_FILE) {
|
||||||
|
state = END_OF_ARCHIVE;
|
||||||
|
break;
|
||||||
|
} else if (result != UNZ_OK) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, outer->rootPath() << "failed to go to next file in archive:" << result);
|
||||||
|
state = BAD_ARCHIVE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
unzClose(zip);
|
unzClose(zip);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ public:
|
|||||||
Stop
|
Stop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SGPath rootPath() const
|
||||||
|
{
|
||||||
|
return _rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ public:
|
|||||||
/// Default constructor, initializes the instance to lat = lon = elev = 0
|
/// Default constructor, initializes the instance to lat = lon = elev = 0
|
||||||
SGGeod(void);
|
SGGeod(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
return an SGGeod for which isValid() returns false.
|
||||||
|
This is necessaerby becuase for historical reasons, ther defaulrt constructor above initialsies to zero,zero,zero
|
||||||
|
which *is*
|
||||||
|
*/
|
||||||
|
static SGGeod invalid();
|
||||||
|
|
||||||
/// Factory from angular values in radians and elevation is 0
|
/// Factory from angular values in radians and elevation is 0
|
||||||
static SGGeod fromRad(double lon, double lat);
|
static SGGeod fromRad(double lon, double lat);
|
||||||
/// Factory from angular values in degrees and elevation is 0
|
/// Factory from angular values in degrees and elevation is 0
|
||||||
|
|||||||
@@ -663,3 +663,8 @@ SGGeodesy::radialIntersection(const SGGeod& a, double aRadial,
|
|||||||
result = SGGeod::fromGeoc(r);
|
result = SGGeod::fromGeoc(r);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGGeod SGGeod::invalid()
|
||||||
|
{
|
||||||
|
return SGGeod::fromDeg(-999.9, -999.0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ void naFreeContext(naContext c)
|
|||||||
// than I have right now. So instead I'm clearing the stack tops here, so
|
// than I have right now. So instead I'm clearing the stack tops here, so
|
||||||
// a freed context looks the same as a new one returned by initContext.
|
// a freed context looks the same as a new one returned by initContext.
|
||||||
|
|
||||||
c->fTop = c->opTop = c->markTop = 0;
|
c->fTop = c->opTop = c->markTop = c->ntemps = 0;
|
||||||
|
|
||||||
c->nextFree = globals->freeContexts;
|
c->nextFree = globals->freeContexts;
|
||||||
globals->freeContexts = c;
|
globals->freeContexts = c;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace nasal
|
|||||||
|
|
||||||
class NasalMainLoopRecipient : public simgear::Emesary::IReceiver {
|
class NasalMainLoopRecipient : public simgear::Emesary::IReceiver {
|
||||||
public:
|
public:
|
||||||
NasalMainLoopRecipient() : receiveCount(0) {
|
NasalMainLoopRecipient() : receiveCount(0), Active(false), CanWait(false) {
|
||||||
simgear::Emesary::GlobalTransmitter::instance()->Register(*this);
|
simgear::Emesary::GlobalTransmitter::instance()->Register(*this);
|
||||||
}
|
}
|
||||||
virtual ~NasalMainLoopRecipient() {
|
virtual ~NasalMainLoopRecipient() {
|
||||||
|
|||||||
@@ -100,7 +100,14 @@ naRef naNewHash(struct Context* c)
|
|||||||
|
|
||||||
naRef naNewCode(struct Context* c)
|
naRef naNewCode(struct Context* c)
|
||||||
{
|
{
|
||||||
return naNew(c, T_CODE);
|
naRef r = naNew(c, T_CODE);
|
||||||
|
// naNew can return a previously used naCode. naCodeGen will init
|
||||||
|
// all these members but a GC can occur inside naCodeGen, so we see
|
||||||
|
// partially initalized state here. To avoid this, clear out the values
|
||||||
|
// which mark() cares about.
|
||||||
|
PTR(r).code->srcFile = naNil();
|
||||||
|
PTR(r).code->nConstants = 0;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
||||||
|
|||||||
@@ -133,7 +133,9 @@ public:
|
|||||||
|
|
||||||
void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
|
void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
|
||||||
{
|
{
|
||||||
for (auto d : delegates) {
|
// take a copy of delegates since firing this can modify the data
|
||||||
|
const auto currentDelegates = delegates;
|
||||||
|
for (auto d : currentDelegates) {
|
||||||
d->catalogRefreshed(catalog, status);
|
d->catalogRefreshed(catalog, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -722,12 +724,6 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
|
|||||||
auto catIt = d->catalogs.find(aCat->id());
|
auto catIt = d->catalogs.find(aCat->id());
|
||||||
d->fireRefreshStatus(aCat, aReason);
|
d->fireRefreshStatus(aCat, aReason);
|
||||||
|
|
||||||
if (aReason == Delegate::STATUS_IN_PROGRESS) {
|
|
||||||
d->refreshing.insert(aCat);
|
|
||||||
} else {
|
|
||||||
d->refreshing.erase(aCat);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aCat->isUserEnabled() &&
|
if (aCat->isUserEnabled() &&
|
||||||
(aReason == Delegate::STATUS_REFRESHED) &&
|
(aReason == Delegate::STATUS_REFRESHED) &&
|
||||||
(catIt == d->catalogs.end()))
|
(catIt == d->catalogs.end()))
|
||||||
@@ -761,6 +757,17 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
|
|||||||
}
|
}
|
||||||
} // of catalog is disabled
|
} // of catalog is disabled
|
||||||
|
|
||||||
|
// remove from refreshing /after/ checking for enable / disabled, since for
|
||||||
|
// new catalogs, the reference in d->refreshing might be our /only/
|
||||||
|
// reference to the catalog. Once the refresh is done (either failed or
|
||||||
|
// succeeded) the Catalog will be in either d->catalogs or
|
||||||
|
// d->disabledCatalogs
|
||||||
|
if (aReason == Delegate::STATUS_IN_PROGRESS) {
|
||||||
|
d->refreshing.insert(aCat);
|
||||||
|
} else {
|
||||||
|
d->refreshing.erase(aCat);
|
||||||
|
}
|
||||||
|
|
||||||
if (d->refreshing.empty()) {
|
if (d->refreshing.empty()) {
|
||||||
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
||||||
d->firePackagesChanged();
|
d->firePackagesChanged();
|
||||||
|
|||||||
+25
-14
@@ -19,6 +19,10 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <exception> // can't use sg_exception becuase of PROPS_STANDALONE
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -51,6 +55,10 @@ using namespace simgear;
|
|||||||
|
|
||||||
struct SGPropertyNodeListeners
|
struct SGPropertyNodeListeners
|
||||||
{
|
{
|
||||||
|
/* Protect _num_iterators and _items. We use a recursive mutex to allow
|
||||||
|
nested access to work as normal. */
|
||||||
|
std::recursive_mutex _rmutex;
|
||||||
|
|
||||||
/* This keeps a count of the current number of nested invocations of
|
/* This keeps a count of the current number of nested invocations of
|
||||||
forEachListener(). If non-zero, other code higher up the stack is iterating
|
forEachListener(). If non-zero, other code higher up the stack is iterating
|
||||||
_items[] so for example code must not erase items in the vector. */
|
_items[] so for example code must not erase items in the vector. */
|
||||||
@@ -558,23 +566,15 @@ find_node (SGPropertyNode * current,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template<typename Range>
|
template <typename Range>
|
||||||
SGPropertyNode*
|
SGPropertyNode *find_node(SGPropertyNode *current, const Range &path,
|
||||||
find_node (SGPropertyNode * current,
|
bool create, int last_index = -1) {
|
||||||
const Range& path,
|
|
||||||
bool create,
|
|
||||||
int last_index = -1)
|
|
||||||
{
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
typedef split_iterator<typename range_result_iterator<Range>::type>
|
auto itr = make_split_iterator(path, first_finder("/", is_equal()));
|
||||||
PathSplitIterator;
|
|
||||||
|
|
||||||
PathSplitIterator itr
|
|
||||||
= make_split_iterator(path, first_finder("/", is_equal()));
|
|
||||||
if (*path.begin() == '/')
|
if (*path.begin() == '/')
|
||||||
return find_node_aux(current->getRootNode(), itr, create, last_index);
|
return find_node_aux(current->getRootNode(), itr, create, last_index);
|
||||||
else
|
else
|
||||||
return find_node_aux(current, itr, create, last_index);
|
return find_node_aux(current, itr, create, last_index);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2406,6 +2406,7 @@ SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
|
|||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
_listeners = new SGPropertyNodeListeners;
|
_listeners = new SGPropertyNodeListeners;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
/* If there's a nullptr entry (a listener that was unregistered), we
|
/* If there's a nullptr entry (a listener that was unregistered), we
|
||||||
overwrite it. This ensures that listeners that routinely unregister+register
|
overwrite it. This ensures that listeners that routinely unregister+register
|
||||||
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
||||||
@@ -2429,9 +2430,13 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
{
|
{
|
||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
return;
|
return;
|
||||||
|
/* We use a std::unique_lock rather than a std::lock_guard because we may
|
||||||
|
need to unlock early. */
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
vector<SGPropertyChangeListener*>::iterator it =
|
vector<SGPropertyChangeListener*>::iterator it =
|
||||||
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
||||||
if (it != _listeners->_items.end()) {
|
if (it != _listeners->_items.end()) {
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
if (_listeners->_num_iterators) {
|
if (_listeners->_num_iterators) {
|
||||||
/* _listeners._items is currently being iterated further up the stack in
|
/* _listeners._items is currently being iterated further up the stack in
|
||||||
this thread by one or more nested invocations of forEachListener(), so
|
this thread by one or more nested invocations of forEachListener(), so
|
||||||
@@ -2450,6 +2455,7 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
_listeners->_items.erase(it);
|
_listeners->_items.erase(it);
|
||||||
listener->unregister_property(this);
|
listener->unregister_property(this);
|
||||||
if (_listeners->_items.empty()) {
|
if (_listeners->_items.empty()) {
|
||||||
|
lock.unlock();
|
||||||
delete _listeners;
|
delete _listeners;
|
||||||
_listeners = 0;
|
_listeners = 0;
|
||||||
}
|
}
|
||||||
@@ -2512,6 +2518,8 @@ static void forEachListener(
|
|||||||
{
|
{
|
||||||
if (!_listeners) return;
|
if (!_listeners) return;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
_listeners->_num_iterators += 1;
|
_listeners->_num_iterators += 1;
|
||||||
|
|
||||||
/* We need to use an index here when iterating _listeners->_items, not an
|
/* We need to use an index here when iterating _listeners->_items, not an
|
||||||
@@ -2530,8 +2538,10 @@ static void forEachListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_listeners->_num_iterators -= 1;
|
_listeners->_num_iterators -= 1;
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
|
|
||||||
if (_listeners->_num_iterators == 0) {
|
if (_listeners->_num_iterators == 0) {
|
||||||
|
|
||||||
/* Remove any items that have been set to nullptr. */
|
/* Remove any items that have been set to nullptr. */
|
||||||
_listeners->_items.erase(
|
_listeners->_items.erase(
|
||||||
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
||||||
@@ -2547,6 +2557,7 @@ static void forEachListener(
|
|||||||
int SGPropertyNode::nListeners() const
|
int SGPropertyNode::nListeners() const
|
||||||
{
|
{
|
||||||
if (!_listeners) return 0;
|
if (!_listeners) return 0;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto listener: _listeners->_items) {
|
for (auto listener: _listeners->_items) {
|
||||||
if (listener) n += 1;
|
if (listener) n += 1;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
#include <simgear/structure/SGExpression.hxx>
|
#include <simgear/structure/SGExpression.hxx>
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
#include <simgear/props/vectorPropTemplates.hxx>
|
#include <simgear/props/vectorPropTemplates.hxx>
|
||||||
|
#include <simgear/debug/ErrorReportingCallback.hxx>
|
||||||
#include <simgear/io/iostreams/sgstream.hxx>
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -928,7 +928,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
|
|||||||
// FIXME orig: const string& shaderName = shaderKey.first;
|
// FIXME orig: const string& shaderName = shaderKey.first;
|
||||||
string shaderName = shaderKey.first;
|
string shaderName = shaderKey.first;
|
||||||
Shader::Type stype = (Shader::Type)shaderKey.second;
|
Shader::Type stype = (Shader::Type)shaderKey.second;
|
||||||
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false) &&
|
const bool compositorEnabled = getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false);
|
||||||
|
if (compositorEnabled &&
|
||||||
shaderName.substr(0, shaderName.find("/")) == "Shaders") {
|
shaderName.substr(0, shaderName.find("/")) == "Shaders") {
|
||||||
shaderName = "Compositor/" + shaderName;
|
shaderName = "Compositor/" + shaderName;
|
||||||
}
|
}
|
||||||
@@ -936,7 +937,9 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
|
|||||||
if (fileName.empty())
|
if (fileName.empty())
|
||||||
{
|
{
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName);
|
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName);
|
||||||
|
if (!compositorEnabled) {
|
||||||
|
reportError("Missing shader", shaderName);
|
||||||
|
}
|
||||||
|
|
||||||
throw BuilderException(string("couldn't find shader ") +
|
throw BuilderException(string("couldn't find shader ") +
|
||||||
shaderName);
|
shaderName);
|
||||||
@@ -1481,10 +1484,8 @@ void mergeSchemesFallbacks(Effect *effect, const SGReaderWriterOptions *options)
|
|||||||
|
|
||||||
// Walk the techniques property tree, building techniques and
|
// Walk the techniques property tree, building techniques and
|
||||||
// passes.
|
// passes.
|
||||||
static std::mutex realizeTechniques_lock;
|
|
||||||
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
|
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> g(realizeTechniques_lock);
|
|
||||||
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false))
|
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false))
|
||||||
mergeSchemesFallbacks(this, options);
|
mergeSchemesFallbacks(this, options);
|
||||||
|
|
||||||
|
|||||||
@@ -273,11 +273,19 @@ bool setAttrs(const TexTuple& attrs, Texture* tex,
|
|||||||
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED);
|
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED);
|
||||||
else
|
else
|
||||||
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS);
|
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS);
|
||||||
#if OSG_VERSION_LESS_THAN(3,4,2)
|
|
||||||
result = osgDB::readImageFile(imageName, options);
|
try {
|
||||||
#else
|
#if OSG_VERSION_LESS_THAN(3,4,2)
|
||||||
result = osgDB::readRefImageFile(imageName, options);
|
result = osgDB::readImageFile(imageName, options);
|
||||||
#endif
|
#else
|
||||||
|
result = osgDB::readRefImageFile(imageName, options);
|
||||||
|
#endif
|
||||||
|
} catch (std::bad_alloc& ba) {
|
||||||
|
SG_LOG(SG_GL, SG_ALERT, "Bad allocation loading:" << imageName);
|
||||||
|
// todo: report low memory warning
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
options->setLoadOriginHint(origLOH);
|
options->setLoadOriginHint(origLOH);
|
||||||
osg::ref_ptr<osg::Image> image;
|
osg::ref_ptr<osg::Image> image;
|
||||||
if (result.success())
|
if (result.success())
|
||||||
|
|||||||
@@ -393,6 +393,10 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
isEffect = true;
|
isEffect = true;
|
||||||
// can_compress = false;
|
// can_compress = false;
|
||||||
}
|
}
|
||||||
|
else if (sgoptC && !transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_CANVAS) {
|
||||||
|
SG_LOG(SG_IO, SG_INFO, "From Canvas " + absFileName + " will generate mipmap only");
|
||||||
|
can_compress = false;
|
||||||
|
}
|
||||||
if (can_compress)
|
if (can_compress)
|
||||||
{
|
{
|
||||||
std::string pot_message;
|
std::string pot_message;
|
||||||
|
|||||||
@@ -1135,16 +1135,8 @@ void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||||||
double intPart;
|
double intPart;
|
||||||
double rot = modf(rotation, &intPart);
|
double rot = modf(rotation, &intPart);
|
||||||
double angle = rot * 2.0 * osg::PI;
|
double angle = rot * 2.0 * osg::PI;
|
||||||
const SGVec3d& sgcenter = transform->getCenter();
|
transform->setAngleRad(angle);
|
||||||
const SGVec3d& sgaxis = transform->getAxis();
|
|
||||||
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
|
|
||||||
* Matrixd::rotate(angle, sgaxis[0], sgaxis[1], sgaxis[2])
|
|
||||||
* Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2])
|
|
||||||
* *cv->getModelViewMatrix();
|
|
||||||
ref_ptr<RefMatrix> refmat = new RefMatrix(mat);
|
|
||||||
cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame());
|
|
||||||
traverse(transform, nv);
|
traverse(transform, nv);
|
||||||
cv->popModelViewMatrix();
|
|
||||||
} else {
|
} else {
|
||||||
traverse(transform, nv);
|
traverse(transform, nv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& opti
|
|||||||
osg::ref_ptr<osg::Node>
|
osg::ref_ptr<osg::Node>
|
||||||
ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const
|
ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const
|
||||||
{
|
{
|
||||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
osg::ref_ptr<osg::PagedLOD> pagedLOD = new osg::PagedLOD;
|
||||||
|
|
||||||
pagedLOD->setCenterMode(osg::PagedLOD::USER_DEFINED_CENTER);
|
pagedLOD->setCenterMode(osg::PagedLOD::USER_DEFINED_CENTER);
|
||||||
SGSpheref sphere = bucketBox.getBoundingSphere();
|
SGSpheref sphere = bucketBox.getBoundingSphere();
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
||||||
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
||||||
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
||||||
group->setName("STG-group-A");
|
string group_name = string("STG-group-A ").append(_bucket.gen_index_str());
|
||||||
|
group->setName(group_name);
|
||||||
group->setDataVariance(osg::Object::STATIC);
|
group->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
||||||
@@ -586,10 +587,12 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
{
|
{
|
||||||
osg::ref_ptr<SGReaderWriterOptions> options;
|
osg::ref_ptr<SGReaderWriterOptions> options;
|
||||||
options = SGReaderWriterOptions::copyOrCreate(opt);
|
options = SGReaderWriterOptions::copyOrCreate(opt);
|
||||||
|
float pagedLODExpiry = atoi(options->getPluginStringData("SimGear::PAGED_LOD_EXPIRY").c_str());
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
||||||
terrainGroup->setDataVariance(osg::Object::STATIC);
|
terrainGroup->setDataVariance(osg::Object::STATIC);
|
||||||
terrainGroup->setName("terrain");
|
std::string terrain_name = string("terrain ").append(bucket.gen_index_str());
|
||||||
|
terrainGroup->setName(terrain_name);
|
||||||
|
|
||||||
if (_foundBase) {
|
if (_foundBase) {
|
||||||
for (auto stgObject : _objectList) {
|
for (auto stgObject : _objectList) {
|
||||||
@@ -637,11 +640,13 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
} else {
|
} else {
|
||||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||||
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||||
pagedLOD->setName("pagedObjectLOD");
|
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
|
||||||
|
pagedLOD->setName(name);
|
||||||
|
|
||||||
// This should be visible in any case.
|
// This should be visible in any case.
|
||||||
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
||||||
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
||||||
|
pagedLOD->setMinimumExpiryTime(0, pagedLODExpiry);
|
||||||
|
|
||||||
// we just need to know about the read file callback that itself holds the data
|
// we just need to know about the read file callback that itself holds the data
|
||||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||||
@@ -658,10 +663,11 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
|
|
||||||
// Objects may end up displayed up to 2x the object range.
|
// Objects may end up displayed up to 2x the object range.
|
||||||
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
||||||
|
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
|
||||||
pagedLOD->setRadius(SG_TILE_RADIUS);
|
pagedLOD->setRadius(SG_TILE_RADIUS);
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Range: " << (2.0 * _object_range_rough));
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Range: " << (2.0 * _object_range_rough));
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Radius: " << SG_TILE_RADIUS);
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
|
||||||
return pagedLOD;
|
return pagedLOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,6 +441,10 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
|
|||||||
if (hash_pos != std::string::npos)
|
if (hash_pos != std::string::npos)
|
||||||
line.resize(hash_pos);
|
line.resize(hash_pos);
|
||||||
|
|
||||||
|
if (line.empty()) {
|
||||||
|
continue; // skip blank lines
|
||||||
|
}
|
||||||
|
|
||||||
// and process further
|
// and process further
|
||||||
std::stringstream in(line);
|
std::stringstream in(line);
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <simgear/scene/material/EffectGeode.hxx>
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
#include <simgear/scene/material/mat.hxx>
|
#include <simgear/scene/material/mat.hxx>
|
||||||
#include <simgear/scene/material/matlib.hxx>
|
#include <simgear/scene/material/matlib.hxx>
|
||||||
|
#include <simgear/scene/model/BoundingVolumeBuildVisitor.hxx>
|
||||||
#include <simgear/scene/util/OsgMath.hxx>
|
#include <simgear/scene/util/OsgMath.hxx>
|
||||||
#include <simgear/scene/util/VectorArrayAdapter.hxx>
|
#include <simgear/scene/util/VectorArrayAdapter.hxx>
|
||||||
#include <simgear/scene/util/SGNodeMasks.hxx>
|
#include <simgear/scene/util/SGNodeMasks.hxx>
|
||||||
@@ -340,5 +341,10 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib, int latPoints,
|
|||||||
transform->addChild(geode);
|
transform->addChild(geode);
|
||||||
transform->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
|
transform->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
|
||||||
|
|
||||||
|
// Create a BVH at this point. This is normally provided by the file loader, but as we create the
|
||||||
|
// geometry programmatically, no file loader is involved.
|
||||||
|
BoundingVolumeBuildVisitor bvhBuilder(false);
|
||||||
|
transform->accept(bvhBuilder);
|
||||||
|
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -572,6 +572,15 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
|
|||||||
notFound(slot.currentItem);
|
notFound(slot.currentItem);
|
||||||
} else if (res != HTTPRepository::REPO_NO_ERROR) {
|
} else if (res != HTTPRepository::REPO_NO_ERROR) {
|
||||||
fail(slot.currentItem);
|
fail(slot.currentItem);
|
||||||
|
|
||||||
|
// in case the Airports_archive download fails, create the
|
||||||
|
// directory, so that next sync, we do a manual sync
|
||||||
|
if ((slot.currentItem._type == SyncItem::AirportData) && slot.isNewDirectory) {
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_ALERT, "Failed to download Airports_archive, will download discrete files next time");
|
||||||
|
simgear::Dir d(_local_dir + "/Airports");
|
||||||
|
d.create(0755);
|
||||||
|
_completedTiles.erase(slot.currentItem._dir);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updated(slot.currentItem, slot.isNewDirectory);
|
updated(slot.currentItem, slot.isNewDirectory);
|
||||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
ORIGIN_EFFECTS,
|
ORIGIN_EFFECTS,
|
||||||
ORIGIN_EFFECTS_NORMALIZED,
|
ORIGIN_EFFECTS_NORMALIZED,
|
||||||
ORIGIN_SPLASH_SCREEN,
|
ORIGIN_SPLASH_SCREEN,
|
||||||
|
ORIGIN_CANVAS,
|
||||||
};
|
};
|
||||||
|
|
||||||
//SGReaderWriterOptions* cloneOptions(const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) const { return static_cast<SGReaderWriterOptions*>(clone(copyop)); }
|
//SGReaderWriterOptions* cloneOptions(const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) const { return static_cast<SGReaderWriterOptions*>(clone(copyop)); }
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
|||||||
std::string nm = stateDesc->getStringValue("name");
|
std::string nm = stateDesc->getStringValue("name");
|
||||||
|
|
||||||
if (nm.empty()) {
|
if (nm.empty()) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No name found for state in branch " << path);
|
SG_LOG(SG_GENERAL, SG_DEV_ALERT, "No name found for state in branch " << path);
|
||||||
throw sg_exception("No name element in state");
|
throw sg_exception("No name element in state");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,8 +464,8 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
|||||||
std::string target_id = tDesc->getStringValue("target");
|
std::string target_id = tDesc->getStringValue("target");
|
||||||
|
|
||||||
if (nm.empty()) {
|
if (nm.empty()) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No name found for transition in branch " << path);
|
SG_LOG(SG_GENERAL, SG_DEV_WARN, "No name found for transition in branch " << path);
|
||||||
throw sg_exception("No name element in transition");
|
nm = "transition-to-" + target_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_id.empty()) {
|
if (target_id.empty()) {
|
||||||
|
|||||||
@@ -30,9 +30,10 @@
|
|||||||
#include "subsystem_mgr.hxx"
|
#include "subsystem_mgr.hxx"
|
||||||
#include "commands.hxx"
|
#include "commands.hxx"
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
|
||||||
#include "SGSmplstat.hxx"
|
#include "SGSmplstat.hxx"
|
||||||
|
#include <simgear/debug/ErrorReportingCallback.hxx>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
|
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
|
||||||
const char SUBSYSTEM_NAME_SEPARATOR = '.';
|
const char SUBSYSTEM_NAME_SEPARATOR = '.';
|
||||||
@@ -828,8 +829,18 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
|
|||||||
if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
|
if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
|
SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
|
||||||
", suspending)");
|
", suspending)");
|
||||||
|
simgear::reportError("suspending subsystem after too many errors:" + name);
|
||||||
subsystem->suspend();
|
subsystem->suspend();
|
||||||
}
|
}
|
||||||
|
} catch (std::bad_alloc& ba) {
|
||||||
|
// attempting to track down source of these on Sentry.io
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "caught bad_alloc processing subsystem:" << name);
|
||||||
|
simgear::reportError("caught bad_alloc processing subsystem:" + name);
|
||||||
|
|
||||||
|
if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount << ", suspending)");
|
||||||
|
subsystem->suspend();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user