Skip to content

Commit a5001e5

Browse files
authored
[MAJOR] Simplify the design (#1)
* Simplify design by merging editor item and settings entry concepts * Remove unnecessary attributes from types fbs * Update file management according to new design * Completed the design * Fix mixing entries between different versions * Fix using undefined version when the entry has no default buffer * Add target name to entry * Fix not updating editor's entry at registration * Remove duplicated editor message * Add cpp helpers for RegisterEntry * Fix compile warnings * Fix resetting update callback * Fix locking the same entry twice * Parameter const nosBuffer* Buffer -> nosBuffer DefaultValueBuffer * Rename TargetName->UiTargetName * Rename Main.h->EntryManager.h * Remove IsEditableFromEditor field * Rename TryToGetClosestFittingEntry and add a description as comment * Use const char* instead of nosName * Remove plugins deciding entry file directory and add it to editor events (default is workspace for now) * Listen to post unloads for automatic unregistration
1 parent 2423a32 commit a5001e5

File tree

11 files changed

+504
-351
lines changed

11 files changed

+504
-351
lines changed

Config/EditorEvents.fbs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,26 @@ attribute "resource";
1313
attribute "strict_type";
1414

1515
table SettingsUpdateFromEditor{
16-
module_name: string;
16+
plugin_name: string;
1717
entry: nos.sys.settings.SettingsEntry;
1818
}
1919

20+
enum SettingsEntryFileDirectory : uint{
21+
LOCAL = 0,
22+
WORKSPACE = 1,
23+
GLOBAL = 2
24+
}
25+
2026
// Editor will use this structure to display settings
2127
table SettingsEditorItem{
2228
item_display_name:string (key);
2329
visualizer: nos.fb.Visualizer;
2430
entry: nos.sys.settings.SettingsEntry;
31+
directory: SettingsEntryFileDirectory;
2532
}
2633

2734
// List of items to be displayed in the editor
2835
table SettingsUpdateFromSubsystem{
29-
module_name: string;
36+
plugin_name: string;
3037
settings: [SettingsEditorItem];
3138
}

Config/Types.fbs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,17 @@
11
namespace nos.sys.settings;
22

3-
attribute "hidden_property";
4-
attribute "units";
5-
attribute "builtin";
6-
attribute "skip_make";
7-
attribute "skip_break";
8-
attribute "skip_delay";
93
attribute "dynamic";
10-
attribute "resource";
11-
attribute "strict_type";
124
attribute "key";
135

146
table SettingsEntry{
157
entry_name: string (key);
168
type_name: string;
9+
ui_target_name: string;
1710
data: [ubyte] (dynamic: "type_name");
1811
}
1912

20-
table ModuleSettings{
21-
module_name:string;
22-
module_version:string;
13+
// This is the root table for the global settings file.
14+
// If you change this or any subtable, you should bump minor version
15+
table SettingsList{
2316
settings: [SettingsEntry];
24-
}
25-
26-
table ModuleSettingsList{
27-
module_settings: [ModuleSettings];
2817
}

Include/nosSettingsSubsystem/nosSettingsSubsystem.h

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,46 @@
66
#define NOS_SETTINGS_SUBSYSTEM_H_INCLUDED
77
#include "Nodos/Types.h"
88

9-
typedef enum nosSettingsFileDirectory {
10-
NOS_SETTINGS_FILE_DIRECTORY_LOCAL, // Module's root folder
11-
NOS_SETTINGS_FILE_DIRECTORY_WORKSPACE, // Engine's config folder
12-
NOS_SETTINGS_FILE_DIRECTORY_GLOBAL // AppData folder
13-
} nosSettingsFileDirectory;
14-
15-
typedef nosResult(*nosPfnSettingsItemUpdate)(const char* entryName, nosBuffer itemValue);
9+
// NOS_RESULT_SUCCESS: Item value will be serialized to the WriteDirectories
10+
// NOS_RESULT_FAIL: Default item value will be serialized to the WriteDirectories
11+
typedef nosResult(*nosPfnSettingsEntryUpdate)(const char* entryName, nosBuffer itemValue);
12+
typedef uint64_t nosSettingsEntryId;
1613

1714
#if NOS_HAS_CPLUSPLUS_20
18-
#include "EditorEvents_generated.h"
19-
typedef nos::sys::settings::editor::SettingsEditorItem nosSettingsEditorItem;
15+
typedef nos::fb::Visualizer* nosSettingsEditorVisualizer;
2016
#else
21-
typedef void* nosSettingsEditorItem;
17+
typedef void* nosSettingsEditorVisualizer;
2218
#endif
2319

2420
typedef struct nosSettingsEntryParams {
2521
nosName TypeName;
26-
nosBuffer Buffer; // Don't forget to free this buffer
22+
// Default value of the buffer
23+
// If nosPfnSettingsEntryUpdate callback returns NOS_SETTINGS_ENTRY_NON_COMPATIBLE, this will be saved
24+
// Don't forget to free this buffer
25+
nosBuffer DefaultValueBuffer;
2726
const char* EntryName; // If NULL, "default" will be used
28-
nosSettingsFileDirectory Directory;
27+
nosPfnSettingsEntryUpdate UpdateCallback; // Callback to update the entry value
28+
nosSettingsEditorVisualizer Visualizer; // Visualizer for the entry in editor
29+
const char* DisplayName;
30+
// Target module name, editor can decide where to place this entry
31+
// For example, if this is "nos.sys.device", editor can place this entry under "Devices" section
32+
const char* UiTargetName;
2933
} nosSettingsEntryParams;
3034

3135
typedef struct nosSettingsSubsystem
3236
{
33-
// parameters->directory will be set to found directory
34-
// if parameters->typeName == 0, it will be set to first typename found in the closest file
35-
// parameters->directory is ignored because closest one is chosen
36-
nosResult(NOSAPI_CALL *ReadSettingsEntry)(nosSettingsEntryParams* parameters);
37-
// parameters->typeName should be a valid typename
38-
// if parameters->directory is not set, it will be set to NOS_SETTINGS_FILE_DIRECTORY_LOCAL
39-
nosResult(NOSAPI_CALL *WriteSettingsEntry)(const nosSettingsEntryParams* parameters);
40-
41-
42-
// Editor related functions
43-
44-
nosResult(NOSAPI_CALL *RegisterEditorSettings)(u64 itemCount, const nosSettingsEditorItem** itemList, nosPfnSettingsItemUpdate itemUpdateCallback, nosSettingsFileDirectory saveDirectory);
45-
nosResult(NOSAPI_CALL *UnregisterEditorSettings)();
37+
nosResult(NOSAPI_CALL *RegisterEntry)(const nosSettingsEntryParams* parameters);
38+
nosResult(NOSAPI_CALL* UpdateEntryValue)(const char* entryName, nosBuffer value);
39+
// An entry can only be unregistered by the plugin it's registered from
40+
void(NOSAPI_CALL* UnregisterEntry)(const char* entryName);
4641
} nosSettingsSubsystem;
4742

4843
#pragma region Helper Declarations & Macros
4944
// Make sure these are same with nossys file.
5045
#define NOS_SETTINGS_SUBSYSTEM_NAME "nos.sys.settings"
5146

52-
#define NOS_SETTINGS_SUBSYSTEM_VERSION_MAJOR 0
53-
#define NOS_SETTINGS_SUBSYSTEM_VERSION_MINOR 10
47+
#define NOS_SETTINGS_SUBSYSTEM_VERSION_MAJOR 1
48+
#define NOS_SETTINGS_SUBSYSTEM_VERSION_MINOR 0
5449

5550
extern struct nosPluginInfo nosSettingsModuleInfo;
5651
extern nosSettingsSubsystem* nosSettings;
@@ -61,6 +56,43 @@ extern nosSettingsSubsystem* nosSettings;
6156

6257
#define NOS_SETTINGS_IMPORT() NOS_IMPORT_DEP(NOS_SETTINGS_SUBSYSTEM_NAME, nosSettingsModuleInfo, nosSettings)
6358

59+
#if NOS_HAS_CPLUSPLUS_20
60+
#include "Types_generated.h"
61+
#include <Nodos/Name.hpp>
62+
63+
namespace nos::sys::settings {
64+
inline nosResult RegisterEntry(std::string const& entryName, std::string const& typeName, nosPfnSettingsEntryUpdate updateCallback, std::optional<nosBuffer> defaultVal = std::nullopt, std::optional<std::string> displayName = std::nullopt, std::optional<std::string> targetName = std::nullopt, std::optional<nos::fb::TVisualizer> visualizer = std::nullopt) {
65+
nosSettingsEntryParams params{};
66+
params.EntryName = entryName.empty() ? NULL : entryName.c_str();
67+
params.TypeName = nos::Name(typeName);
68+
params.UpdateCallback = updateCallback;
69+
70+
if (displayName.has_value() && !displayName->empty())
71+
params.DisplayName = displayName->c_str();
72+
else
73+
params.DisplayName = params.EntryName;
74+
75+
if (defaultVal.has_value())
76+
params.DefaultValueBuffer = *defaultVal;
77+
78+
if (targetName.has_value() && !targetName->empty())
79+
params.UiTargetName = targetName->c_str();
80+
81+
nos::Buffer visualizerBuf;
82+
if (visualizer.has_value()) {
83+
visualizerBuf = nos::Buffer::From(*visualizer);
84+
params.Visualizer = visualizerBuf.As<nos::fb::Visualizer>();
85+
}
86+
87+
return nosSettings->RegisterEntry(&params);
88+
}
89+
90+
inline void UnregisterEntry(std::string const& entryName) {
91+
nosSettings->UnregisterEntry(entryName.c_str());
92+
}
93+
}
94+
#endif // NOS_HAS_CPLUSPLUS_20
95+
6496
#pragma endregion
6597

6698

Settings.nossys

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"info": {
33
"id": {
44
"name": "nos.sys.settings",
5-
"version": "0.10.3"
5+
"version": "1.0.0"
66
},
77
"display_name": "Settings Subsystem",
88
"description": "Store all module settings",

Source/EntryManager.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright Nodos AS. All Rights Reserved.
2+
#include <Nodos/PluginAPI.h>
3+
#include <nosSettingsSubsystem/nosSettingsSubsystem.h>
4+
#include <nosSettingsSubsystem/Types_generated.h>
5+
#include <unordered_map>
6+
#include <Nodos/Helpers.hpp>
7+
#include <nosUtil/StringUtils.h>
8+
#include <nosUtil/VersionUtils.h>
9+
10+
namespace nos::sys::settings
11+
{
12+
13+
struct RegisteredEntry {
14+
nos::Name TypeName;
15+
nos::Buffer LastValue;
16+
editor::SettingsEntryFileDirectory SaveDir;
17+
nos::fb::TVisualizer Visualizer{};
18+
std::string UiTargetName;
19+
std::string DisplayName;
20+
nosPfnSettingsEntryUpdate UpdateCallback = nullptr;
21+
// If an entry with the same name from a previous version of this plugin is already read, save according to it
22+
nos::util::SemVer ReadEntryPluginVer{};
23+
};
24+
25+
typedef std::pair<nos::Name, nos::Buffer> EntryTypeNameBufferPair;
26+
struct ReadEntryList
27+
{
28+
std::shared_mutex FileMutex;
29+
// EntryName -> {PluginVer, {TypeName, Buffer}} (sorted by plugin version)
30+
std::unordered_map<std::string, std::vector<std::pair<nos::util::SemVer, EntryTypeNameBufferPair>>> Entries;
31+
};
32+
33+
nosResult UpdateEditorEntriesForPlugin(nos::Name pluginName);
34+
nosResult UnregisterSettings(nos::Name moduleName);
35+
void OnEditorConnected(uint64_t editorId);
36+
void OnMessageFromEditor(uint64_t editorId, nosBuffer message);
37+
38+
struct EntryManager
39+
{
40+
// PluginName -> EntryName -> RegisteredEntry
41+
std::unordered_map<nos::Name, std::unordered_map<std::string, RegisteredEntry>> RegisteredEntries;
42+
std::shared_mutex RegisteredEntriesMutex;
43+
// PluginName -> { PluginVersion, PluginInfo }
44+
std::unordered_map<nos::Name, std::pair<nos::util::SemVer, nosPluginInfo>> PluginVersions;
45+
// Entries from files
46+
// PluginName -> EntryList
47+
std::unordered_map<nos::Name, ReadEntryList> GlobalEntries, WorkspaceEntries, LocalEntries;
48+
nosResult ReadSettingsFile(std::filesystem::path filePath, ReadEntryList& readEntries);
49+
nosResult WriteSettingsFile(nos::Name pluginName, util::SemVer pluginVer, editor::SettingsEntryFileDirectory dir, const ReadEntryList& entries) const;
50+
// Searches through local, workspace and global settings files
51+
// For each matching entry, calls the UpdateCallback with the entry name and value
52+
// First one to return NOS_RESULT_SUCCESS will be used
53+
// If no matching entry is found, NOS_RESULT_FAILED will be returned
54+
nosResult TryGetOrCreateFromClosestValidEntry(nos::Name pluginName, std::string entryName, RegisteredEntry& entry);
55+
// If there is a matching entry with the same plugin version, updates it
56+
// If there is not, creates a new entry
57+
nosResult UpdateEntry(nos::Name pluginName, nos::util::SemVer pluginVersion, editor::SettingsEntryFileDirectory dir, std::string const& entryName, EntryTypeNameBufferPair entryVal);
58+
};
59+
}

0 commit comments

Comments
 (0)