Skip to content

Commit 0eb38c1

Browse files
authoredMay 27, 2024
Improve bulk upload of DDF bundles and hotreload (dresden-elektronik#7792)
Instead of reloading all DDFs after each upload, wait 2 seconds if more is uploaded before reloading everything. The Phoscon App now supports uploading zipped bundles which may contain hundreds. Further improve hotreload via DDF editor.
1 parent 4f55da6 commit 0eb38c1

4 files changed

+124
-31
lines changed
 

‎device_descriptions.cpp

+110-17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <QJsonObject>
1717
#include <QJsonValue>
1818
#include <QSettings>
19+
#include <QTimer>
1920
#include <deconz/atom_table.h>
2021
#include <deconz/dbg_trace.h>
2122
#include <deconz/file.h>
@@ -106,9 +107,14 @@ struct ConstantEntry
106107
enum DDF_LoadState
107108
{
108109
DDF_LoadStateScheduled,
109-
DDF_LoadStateNotFound,
110-
DDF_LoadStateLoadedRawJson,
111-
DDF_LoadStateLoadedBundle
110+
DDF_LoadStateLoaded
111+
};
112+
113+
enum DDF_ReloadWhat
114+
{
115+
DDF_ReloadIdle,
116+
DDF_ReloadBundles,
117+
DDF_ReloadAll
112118
};
113119

114120
struct DDF_LoadRecord
@@ -141,6 +147,9 @@ class DeviceDescriptionsPrivate
141147

142148
std::vector<DDF_LoadRecord> ddfLoadRecords;
143149
std::vector<U_ECC_PublicKeySecp256k1> publicKeys;
150+
151+
DDF_ReloadWhat ddfReloadWhat = DDF_ReloadIdle;
152+
QTimer *ddfReloadTimer = nullptr;
144153
};
145154

146155
static int DDF_ReadFileInMemory(DDF_ParseContext *pctx);
@@ -165,6 +174,9 @@ DeviceDescriptions::DeviceDescriptions(QObject *parent) :
165174
_instance = this;
166175
_priv = d_ptr2;
167176

177+
d_ptr2->ddfReloadTimer = new QTimer(this);
178+
d_ptr2->ddfReloadTimer->setSingleShot(true);
179+
connect(d_ptr2->ddfReloadTimer, &QTimer::timeout, this, &DeviceDescriptions::ddfReloadTimerFired);
168180

169181
{
170182
// register DDF policy atoms used later on for fast comparisons
@@ -1024,7 +1036,6 @@ void DeviceDescriptions::handleEvent(const Event &event)
10241036
{
10251037
if (event.num() == 0)
10261038
{
1027-
readAll(); // todo read only device specific files?
10281039
}
10291040
}
10301041
}
@@ -1984,7 +1995,7 @@ void DeviceDescriptions::readAllRawJson()
19841995

19851996
std::vector<DDF_SubDeviceDescriptor> subDevices;
19861997

1987-
std::array<deCONZ::StorageLocation, 2> locations = { deCONZ::DdfUserLocation, deCONZ::DdfLocation};
1998+
std::array<deCONZ::StorageLocation, 2> locations = { deCONZ::DdfLocation, deCONZ::DdfUserLocation};
19881999

19892000
for (size_t dit = 0; dit < locations.size(); dit++)
19902001
{
@@ -2135,15 +2146,10 @@ void DeviceDescriptions::readAllRawJson()
21352146

21362147
for (k = 0; k < d->ddfLoadRecords.size(); k++)
21372148
{
2138-
if (d->ddfLoadRecords[k].loadState != DDF_LoadStateScheduled)
2139-
{
2140-
continue;
2141-
}
2142-
21432149
if (mfnameIndex.index == d->ddfLoadRecords[k].mfname.index &&
21442150
modelidIndex.index == d->ddfLoadRecords[k].modelid.index)
21452151
{
2146-
d->ddfLoadRecords[k].loadState = DDF_LoadStateLoadedRawJson;
2152+
//d->ddfLoadRecords[k].loadState = DDF_LoadStateLoadedRawJson;
21472153
scheduled = true;
21482154
break;
21492155
}
@@ -2267,6 +2273,7 @@ static int DDF_ReloadBundleDevices(const char *desc, unsigned descSize, std::vec
22672273
AT_AtomIndex mfname_ati;
22682274
cj_token *tokens;
22692275
unsigned n_tokens = 1024;
2276+
int n_marked = 0;
22702277

22712278
ScratchMemWaypoint swp;
22722279
tokens = SCRATCH_ALLOC(cj_token*, n_tokens * sizeof(*tokens));
@@ -2341,20 +2348,23 @@ static int DDF_ReloadBundleDevices(const char *desc, unsigned descSize, std::vec
23412348

23422349
for (size_t j = 0; j < ddfLoadRecords.size(); j++)
23432350
{
2344-
const DDF_LoadRecord &rec = ddfLoadRecords[j];
2351+
DDF_LoadRecord &rec = ddfLoadRecords[j];
23452352

23462353
if (rec.mfname.index != mfname_ati.index)
23472354
continue;
23482355

23492356
if (rec.modelid.index != modelid_ati.index)
23502357
continue;
23512358

2352-
// trigger DDF reload event for matching devices
2353-
DEV_ReloadDeviceIdendifier(mfname_ati.index, modelid_ati.index);
2359+
if (rec.loadState != DDF_LoadStateScheduled)
2360+
{
2361+
rec.loadState = DDF_LoadStateScheduled;
2362+
n_marked++;
2363+
}
23542364
}
23552365
}
23562366

2357-
return 1;
2367+
return n_marked > 0;
23582368
}
23592369

23602370
static int DDF_IsBundleScheduled(DDF_ParseContext *pctx, const char *desc, unsigned descSize, const std::vector<DDF_LoadRecord> &ddfLoadRecords)
@@ -2479,8 +2489,65 @@ void DEV_DDF_BundleUpdated(unsigned char *data, unsigned dataSize)
24792489
if (DDFB_FindChunk(&bs, "DESC", &chunkSize) == 0)
24802490
return;
24812491

2482-
_instance->readAllBundles(); // this is a bit hard core, but does the job for now
2483-
DDF_ReloadBundleDevices((char*)&bs.data[bs.pos], chunkSize, _priv->ddfLoadRecords);
2492+
if (DDF_ReloadBundleDevices((char*)&bs.data[bs.pos], chunkSize, _priv->ddfLoadRecords) != 0)
2493+
{
2494+
_priv->ddfReloadWhat = DDF_ReloadBundles;
2495+
_priv->ddfReloadTimer->stop();
2496+
_priv->ddfReloadTimer->start(2000);
2497+
}
2498+
}
2499+
2500+
void DeviceDescriptions::reloadAllRawJsonAndBundles(const Resource *resource)
2501+
{
2502+
2503+
const ResourceItem *mfnameItem = resource->item(RAttrManufacturerName);
2504+
const ResourceItem *modelidItem = resource->item(RAttrModelId);
2505+
unsigned mfnameAtomIndex = mfnameItem->atomIndex();
2506+
unsigned modelidAtomIndex = modelidItem->atomIndex();
2507+
2508+
for (size_t j = 0; j < d_ptr2->ddfLoadRecords.size(); j++)
2509+
{
2510+
DDF_LoadRecord &rec = d_ptr2->ddfLoadRecords[j];
2511+
2512+
if (rec.mfname.index != mfnameAtomIndex)
2513+
continue;
2514+
2515+
if (rec.modelid.index != modelidAtomIndex)
2516+
continue;
2517+
2518+
if (rec.loadState != DDF_LoadStateScheduled)
2519+
{
2520+
rec.loadState = DDF_LoadStateScheduled;
2521+
}
2522+
}
2523+
2524+
d_ptr2->ddfReloadWhat = DDF_ReloadAll;
2525+
d_ptr2->ddfReloadTimer->stop();
2526+
d_ptr2->ddfReloadTimer->start(1000);
2527+
}
2528+
2529+
void DeviceDescriptions::ddfReloadTimerFired()
2530+
{
2531+
if (d_ptr2->ddfReloadWhat == DDF_ReloadAll)
2532+
{
2533+
readAll();
2534+
}
2535+
else if (d_ptr2->ddfReloadWhat == DDF_ReloadBundles)
2536+
{
2537+
readAllBundles();
2538+
}
2539+
2540+
d_ptr2->ddfReloadWhat = DDF_ReloadIdle;
2541+
2542+
for (DDF_LoadRecord &rec : d_ptr2->ddfLoadRecords)
2543+
{
2544+
// trigger DDF reload event for matching devices
2545+
if (rec.loadState == DDF_LoadStateScheduled)
2546+
{
2547+
rec.loadState = DDF_LoadStateLoaded;
2548+
DEV_ReloadDeviceIdendifier(rec.mfname.index, rec.modelid.index);
2549+
}
2550+
}
24842551
}
24852552

24862553
/*! Reads all scheduled DDF bundles.
@@ -2789,6 +2856,32 @@ void DeviceDescriptions::handleDDFInitRequest(const Event &event)
27892856

27902857
if (DEV_InitBaseDescriptionForDevice(device, ddf1))
27912858
{
2859+
/*
2860+
* Register all atoms for faster lookups.
2861+
*/
2862+
for (const auto &mfname : ddf1.manufacturerNames)
2863+
{
2864+
const QString m = constantToString(mfname);
2865+
2866+
AT_AtomIndex ati;
2867+
if (AT_AddAtom(m.toUtf8().data(), m.size(), &ati) && ati.index != 0)
2868+
{
2869+
ddf1.mfnameAtomIndices.push_back(ati.index);
2870+
}
2871+
}
2872+
2873+
for (const auto &modelId : ddf1.modelIds)
2874+
{
2875+
const QString m = constantToString(modelId);
2876+
2877+
AT_AtomIndex ati;
2878+
if (AT_AddAtom(m.toUtf8().data(), m.size(), &ati) && ati.index != 0)
2879+
{
2880+
ddf1.modelidAtomIndices.push_back(ati.index);
2881+
}
2882+
}
2883+
2884+
ddf1.storageLocation = deCONZ::DdfUserLocation;
27922885
d->descriptions.push_back(std::move(ddf1));
27932886
DDF_UpdateItemHandlesForIndex(d->descriptions, d->loadCounter, d->descriptions.size() - 1);
27942887
}

‎device_descriptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ public Q_SLOTS:
283283
void readAllRawJson();
284284
void readAllBundles();
285285

286+
void ddfReloadTimerFired();
287+
void reloadAllRawJsonAndBundles(const Resource *resource);
288+
286289
Q_SIGNALS:
287290
void eventNotify(const Event&); //! Emitted \p Event needs to be enqueued in a higher layer.
288291
void loaded();

‎rest_devices.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,11 @@ int RestDevices::putDeviceReloadDDF(const ApiRequest &req, ApiResponse &rsp)
11701170

11711171
if (deviceKey)
11721172
{
1173-
emit eventNotify(Event(RDevices, REventDDFReload, 0, deviceKey));
1173+
Device *device = DEV_GetDevice(plugin->m_devices, deviceKey);
1174+
if (device)
1175+
{
1176+
DeviceDescriptions::instance()->reloadAllRawJsonAndBundles(device);
1177+
}
11741178

11751179
QVariantMap rspItem;
11761180
QVariantMap rspItemState;

‎ui/device_widget.cpp

+6-13
Original file line numberDiff line numberDiff line change
@@ -396,26 +396,19 @@ void DeviceWidget::saveAsDDF()
396396

397397
void DeviceWidget::hotReload()
398398
{
399-
const DeviceDescription &ddf = d->ddfWindow->editor->ddf();
400-
if (!ddf.isValid())
401-
{
402-
return;
403-
}
404399
auto *dd = DeviceDescriptions::instance();
405-
dd->put(ddf);
406400

407401
for (const std::unique_ptr<Device> &dev : *d->devices)
408402
{
409-
const auto &ddf0 = dd->get(&*dev);
410-
411-
if (ddf0.handle == ddf.handle)
403+
if (d->curNode.ext() == dev->key())
412404
{
413-
DBG_Printf(DBG_INFO, "Hot reload device: %s\n", dev->item(RAttrUniqueId)->toCString());
414-
dev->handleEvent(Event(RDevices, REventDDFReload, 0, dev->key()));
405+
dd->reloadAllRawJsonAndBundles(dev.get());
406+
QString mfname = dev->item(RAttrManufacturerName)->toString();
407+
QString modelid = dev->item(RAttrModelId)->toString();
408+
d->ddfWindow->showMessage(tr("DDF reloading devices matching: %1 / %2").arg(mfname, modelid));
409+
break;
415410
}
416411
}
417-
418-
d->ddfWindow->showMessage(tr("DDF reloaded for devices"));
419412
}
420413

421414
void DeviceWidget::enablePermitJoin()

0 commit comments

Comments
 (0)
Please sign in to comment.