add network status indicator and protocol changes

pull/182/head
larteyoh 10 months ago
parent d27afb3054
commit c2bcb891bd

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

@ -38,7 +38,7 @@
<file>qml/pages/OrderCheckoutPage.qml</file>
<file>qml/pages/ProductPage.qml</file>
<file>qml/pages/ProfilePage.qml</file>
<file>qml/pages/subpages/AccountSettingsPage.qml</file>
<file>qml/pages/subpages/AccountPage.qml</file>
<file>qml/pages/subpages/DashboardPage.qml</file>
<file>qml/pages/subpages/MessagesPage.qml</file>
<file>qml/pages/subpages/OrdersPage.qml</file>
@ -90,6 +90,7 @@
<file>assets/images/mask.png</file>
<file>assets/images/monero_symbol.png</file>
<file>assets/images/monero_symbol_white.png</file>
<file>assets/images/nodes.png</file>
<file>assets/images/open_parcel.png</file>
<file>assets/images/order.png</file>
<file>assets/images/paid.png</file>

@ -9,12 +9,20 @@ RowLayout {
id: navBar
readonly property string defaultButtonColor: "#6b5b95"
property bool useDefaultButtonColor: false
function getCheckedButton() {
return navBarButtonGroup.checkedButton;
}
function uncheckAllButtons() {
navBarButtonGroup.checkState = Qt.Unchecked;
}
function checkButtonByIndex(buttonIndex) {
if(buttonIndex == 0) walletButton.checked = true
if(buttonIndex == 1) shopButton.checked = true
if(buttonIndex == 2) messagesButton.checked = true
if(buttonIndex == 3) ordersButton.checked = true
if(buttonIndex == 4) accountButton.checked = true
}
ButtonGroup {
id: navBarButtonGroup
@ -26,7 +34,7 @@ RowLayout {
if(button.text == walletButton.text) {
pageLoader.source = "../pages/subpages/WalletPage.qml"//_stackview.currentIndex = 0
}
if(button.text == dashboardButton.text) {
if(button.text == shopButton.text) {
pageLoader.source = "../pages/subpages/DashboardPage.qml"
}
if(button.text == messagesButton.text) {
@ -35,15 +43,15 @@ RowLayout {
if(button.text == ordersButton.text) {
pageLoader.source = "../pages/subpages/OrdersPage.qml"
}
if(button.text == accountSettingsButton.text) {
pageLoader.source = "../pages/subpages/AccountSettingsPage.qml"
if(button.text == accountButton.text) {
pageLoader.source = "../pages/subpages/AccountPage.qml"
}
}
}
Button {
id: walletButton
text: qsTr("Wallet")
text: qsTr("Funds")
ButtonGroup.group: navBarButtonGroup // attaches a button to a button group
display: AbstractButton.IconOnly
//checkable: true
@ -77,8 +85,8 @@ RowLayout {
}
Button {
id: dashboardButton
text: qsTr("Dashboard")
id: shopButton
text: qsTr("Store")
ButtonGroup.group: navBarButtonGroup
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
hoverEnabled: true
@ -177,8 +185,8 @@ RowLayout {
}
Button {
id: accountSettingsButton
text: qsTr("Account Settings")//qsTr("User")
id: accountButton
text: qsTr("Account")//qsTr("User")
ButtonGroup.group: navBarButtonGroup
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
hoverEnabled: true

@ -18,7 +18,7 @@ Item {
placeholderText: qsTr("Search")
background: Rectangle {
color: (NeroshopComponents.Style.darkTheme) ? "#050506" : "#f9f9fa"
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#efefef"
radius: 5
}
Keys.onEnterPressed: searchButton.activate()

@ -257,7 +257,72 @@ ApplicationWindow {
}
}
//Rectangle {
//}
//}
Rectangle {
id: networkMonitor
width: networkMonitorRow.width; height: footer.height
color: "transparent"
//border.color: "plum"
Row {
id: networkMonitorRow
anchors.centerIn: parent
spacing: 5
Text {
id: peerCounterText
anchors.verticalCenter: parent.verticalCenter
text: "0"
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
Timer {
interval: 5000
running: true
repeat: true
onTriggered: {
peerCounterText.text = Backend.getNetworkPeerCount()
}
}
}
Rectangle {
id: networkStatusIndicator
anchors.verticalCenter: parent.verticalCenter
width: 16; height: width
color: {
let nodeCount = Number(peerCounterText.text)
// Apply the color-coded scale based on the number of online nodes
if (nodeCount >= 1001) {
return "#483d8b"
} else if (nodeCount >= 501) {
return "#4169e1";
} else if (nodeCount >= 101) {
return "#228b22";//"#2e8b57" // Darker shade of green for 101 or more nodes
} else if (nodeCount >= 51) {
return "#81ac2a"; // Green for 51 to 100 nodes
} else if (nodeCount >= 11) {
return "#ffa500"; // Orange for 11 to 50 nodes
} else if (nodeCount >= 1) {
return "#ff4500"; // Orangered for 0 to 10 nodes
} else {
return "#b22222"; // Bright red for 0 nodes
}
}
radius: width / 2
}
}
HoverHandler {
id: networkMonitorHoverHandler
}
NeroshopComponents.Hint {
visible: networkMonitorHoverHandler.hovered
height: contentHeight + 20; width: contentWidth + 20
bottomMargin : footer.height + 5
text: qsTr("Network peers: %1").arg(peerCounterText.text)
pointer.visible: false
}
}
}
/*Row {
width: priceDisplayText.contentWidth

@ -318,10 +318,11 @@ Page {
anchors.horizontalCenter: parent.horizontalCenter//Layout.alignment: Qt.AlignHCenter
width: 500; height: 50//Layout.preferredWidth: 500; Layout.preferredHeight: 50
hoverEnabled: true
text: qsTr("Add to favorites")
property string color: "#d62929"
property string lightColor: "#dd4b4b"
property string darkColor: "#b42222"
text: favorited ? qsTr("Remove from favorites") : qsTr("Add to favorites")
property string color: favorited ? "#29d6d6" : "#d62929"
property string lightColor: favorited ? "#34b4b4" : "#dd4b4b"
property string darkColor: favorited ? "#75dddd" : "#b42222"
property bool favorited: User.hasFavorited(productPage.model.key)
background: Rectangle {
color: parent.hovered ? favoritesButton.lightColor : favoritesButton.color////parent.hovered ? (parent.down ? favoritesButton.darkColor : favoritesButton.lightColor) : favoritesButton.color
border.color: favoritesButton.darkColor//parent.hovered ? favoritesButton.color : favoritesButton.lightColor
@ -334,7 +335,16 @@ Page {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {}
onClicked: {
if(!favorited) {
favorited = true
User.addToFavorites(productPage.model.key)
}
else {
favorited = false
User.removeFromFavorites(productPage.model.key)
}
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
@ -347,7 +357,7 @@ Page {
anchors.horizontalCenter: parent.horizontalCenter//Layout.alignment: Qt.AlignHCenter
width: 500; height: 50//Layout.preferredWidth: 500; Layout.preferredHeight: 50
hoverEnabled: true
text: qsTr("Chat")
text: qsTr("Write a review")
property string color: "#53469f"
property string lightColor: "#6c60b9"
property string darkColor: "#483d8b"

@ -15,11 +15,12 @@ Page {
background: Rectangle {
color: "transparent"
}
property var userModel: Backend.getUser(productModel.seller_id)
property var userModel: Backend.getUser((productModel === null) ? messagesModel.sender_id : productModel.seller_id)
property var productModel: null // <- the product listing that redirected user to this profile page
property var ratingsModel: Backend.getSellerRatings(productModel.seller_id)
property var listingsModel: Backend.getInventory(productModel.seller_id, settingsDialog.hideIllegalProducts)//Backend.getListingsBySearchTerm(productModel.seller_id)
property var ratingsModel: Backend.getSellerRatings((productModel === null) ? messagesModel.sender_id : productModel.seller_id)
property var listingsModel: Backend.getInventory((productModel === null) ? messagesModel.sender_id : productModel.seller_id, settingsDialog.hideIllegalProducts)//Backend.getListingsBySearchTerm(productModel.seller_id)
property var messagesModel: null
ColumnLayout {
anchors.fill: parent
anchors.bottomMargin: 10
@ -158,10 +159,14 @@ Page {
ButtonGroup.group: rateButtonGroup
property int buttonValue: 0
text: qsTr("0")
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: "red"
border.color: parent.checked ? "blue" : "transparent"
border.width: 2
color: parent.checked ? "red" : "#808080"
radius: 5
}
}
@ -172,10 +177,14 @@ Page {
ButtonGroup.group: rateButtonGroup
property int buttonValue: 1
text: qsTr("1")
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: "green"
border.color: parent.checked ? "blue" : "transparent"
border.width: 2
color: parent.checked ? "green" : "#808080"
radius: 5
}
}
@ -363,7 +372,13 @@ Page {
color: backButton.hovered ? NeroshopComponents.Style.neroshopPurpleColor : "#50446f"
}
onClicked: {
pageLoader.setSource("qrc:/qml/pages/ProductPage.qml", {"model": productModel})
if(productModel !== null) {
pageLoader.setSource("qrc:/qml/pages/ProductPage.qml", {"model": productModel})
}
if(messagesModel !== null) {
pageLoader.setSource("qrc:/qml/pages/subpages/MessagesPage.qml")
navBar.checkButtonByIndex(2)
}
}
MouseArea {
anchors.fill: parent

@ -25,6 +25,17 @@ Page {
Text {
id: senderText
text: modelData.sender_id
color: "#4169e1"
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
navBar.uncheckAllButtons()
pageLoader.setSource("qrc:/qml/pages/ProfilePage.qml", { "messagesModel": {"sender_id": modelData.sender_id} })
}
onEntered: parent.color = "blue"
onExited: parent.color = "#4169e1"
}
}
TextArea {
id: contentText

@ -212,6 +212,14 @@ std::vector<uint8_t> neroshop::msgpack::process(const std::vector<uint8_t>& requ
auto params_object = request_object["args"];
assert(params_object["key"].is_string());
std::string key = params_object["key"];
// To get network status
if(key == "status") {
response_object["version"] = std::string(NEROSHOP_DHT_VERSION);
response_object["response"]["id"] = node.get_id();
response_object["response"]["connected_peers"] = node.get_peer_count();
response = nlohmann::json::to_msgpack(response_object);
return response;
}
// Send get messages to the closest nodes in your routing table (IPC mode)
std::string value = node.send_get(key);

@ -928,7 +928,7 @@ void neroshop::Node::periodic_refresh() {
//-----------------------------------------------------------------------------
void neroshop::Node::periodic_check() {
std::vector<std::string> dead_node_ids {};
////std::vector<std::string> dead_node_ids {};
while(true) {
{
// Acquire the lock before accessing the routing table
@ -957,7 +957,7 @@ void neroshop::Node::periodic_check() {
if(node->is_dead()) {
std::cout << "\033[0;91m" << node->public_ip_address << ":" << node_port << "\033[0m marked as dead\n";
if(routing_table->has_node(node->public_ip_address, node_port)) {
dead_node_ids.push_back(node->get_id());
////dead_node_ids.push_back(node->get_id());
routing_table->remove_node(node->public_ip_address, node_port); // Already has internal write_lock
}
}
@ -966,9 +966,9 @@ void neroshop::Node::periodic_check() {
// read_lock is released here
}
on_dead_node(dead_node_ids);
/*on_dead_node(dead_node_ids);
// Clear the vector for the next iteration
dead_node_ids.clear();
dead_node_ids.clear();*/
// Sleep for a specified interval
std::this_thread::sleep_for(std::chrono::seconds(NEROSHOP_DHT_PERIODIC_CHECK_INTERVAL));
}
@ -1039,7 +1039,7 @@ void neroshop::Node::on_ping(const std::vector<uint8_t>& buffer, const struct so
//-----------------------------------------------------------------------------
void neroshop::Node::on_dead_node(const std::vector<std::string>& node_ids) {
/*void neroshop::Node::on_dead_node(const std::vector<std::string>& node_ids) {
for (const auto& dead_node_id : node_ids) {
//std::cout << "Processing dead node ID: " << dead_node_id << std::endl;
@ -1076,7 +1076,7 @@ void neroshop::Node::on_dead_node(const std::vector<std::string>& node_ids) {
}
}
}
}
}*/
//-----------------------------------------------------------------------------
@ -1271,6 +1271,10 @@ neroshop::RoutingTable * neroshop::Node::get_routing_table() const {
return routing_table.get();
}
int neroshop::Node::get_peer_count() const {
return routing_table->get_node_count();
}
neroshop::NodeStatus neroshop::Node::get_status() const {
if(check_counter == 0) return NodeStatus::Active;
if(check_counter <= (NEROSHOP_DHT_MAX_HEALTH_CHECKS - 1)) return NodeStatus::Idle;

@ -91,7 +91,7 @@ public:
bool validate(const std::string& key, const std::string& value); // Validates data before storing it
//---------------------------------------------------
void on_ping(const std::vector<uint8_t>& buffer, const struct sockaddr_in& client_addr);
void on_dead_node(const std::vector<std::string>& node_ids);
////void on_dead_node(const std::vector<std::string>& node_ids);
////bool on_keyword_blocked(const std::string& keyword);
////bool on_node_blacklisted(const std::string& address);
////bool on_data_expired();
@ -119,6 +119,7 @@ public:
std::string get_public_ip_address() const;
uint16_t get_port() const;
RoutingTable * get_routing_table() const;
int get_peer_count() const;
NodeStatus get_status() const;
std::string get_status_as_string() const;
std::vector<std::string> get_keys() const;

@ -109,6 +109,13 @@ void rpc_server(const std::string& address) {
//-----------------------------------------------------------------------------
void ipc_server(Node& node) {
// Prevent bootstrap node from being accepted by IPC server
// since its only meant to act as an initial contact point for new nodes joining the network
if (node.is_bootstrap_node()) {
std::cout << "Bootstrap node is not allowed to use the IPC server. Please start another daemon instance to use the GUI\n";
return;
}
Server server("127.0.0.1", NEROSHOP_IPC_DEFAULT_PORT);
while (running) {

@ -1853,4 +1853,26 @@ bool neroshop::Backend::loginWithHW(WalletController* wallet_controller, UserCon
}
//----------------------------------------------------------------
//----------------------------------------------------------------
int neroshop::Backend::getNetworkPeerCount() const {
Client * client = Client::get_main_client();
// Get network status from local node in IPC mode
std::string response;
client->get("status", response); //std::cout << "Received response (get): " << response << "\n";
// Parse the response
nlohmann::json json = nlohmann::json::parse(response);
if(json.contains("error")) {
return 0;
}
const auto& response_obj = json["response"];
assert(response_obj.is_object());
if (response_obj.contains("connected_peers") && response_obj["connected_peers"].is_number_integer()) {
int connected_peers = response_obj["connected_peers"].get<int>();
return connected_peers;
}
return 0;
}
//----------------------------------------------------------------

@ -115,6 +115,8 @@ public:
Q_INVOKABLE void createOrder(UserController * user_controller, const QString& shipping_address);
bool isIllicitItem(const QVariantMap& listing_obj);
Q_INVOKABLE int getNetworkPeerCount() const;
signals:
//void categoryProductCountChanged();//(int category_id);

@ -532,7 +532,7 @@ QVariantList neroshop::UserController::getMessages() const {
message_object.insert("content", QString::fromStdString(message_decrypted.first));
message_object.insert("sender_id", QString::fromStdString(message_decrypted.second));
message_object.insert("recipient_id", QString::fromStdString(value_obj["recipient_id"].get<std::string>()));
if(message_object.contains("timestamp")) message_object.insert("timestamp", QString::fromStdString(value_obj["timestamp"].get<std::string>()));
message_object.insert("timestamp", QString::fromStdString(value_obj["timestamp"].get<std::string>()));
}
messages_array.append(message_object);
}

Loading…
Cancel
Save