Bienvenue sur le forum !

Si vous souhaitez rejoindre la communauté, cliquez sur l'un de ces boutons !

Qt : 5.11.2 - Qt Creator : 4.7.1 - Qt Installer : 3.0.4 - JOM : 1.1.2 - QBS : 1.12.1

Plusieurs applications travaillant sur les mêmes données

Bonjour à tous,

Je viens ici dans l'espoir d'avoir un retour d'expérience et autres remarques.
J'ai codé un outil : RCM (Rolisteam convention manager).
Il est écrit en C++/Qt et QML, il permet de prendre les inscriptions lors d'une convention de jeu de rôle.

https://github.com/obiwankennedy/rcm

Il a été un peu codé à l'arrache mais il fonctionne dans l'ensemble.
Le principal problème est que cela provoque un goulot d'étranglement.
Il n'y a qu'une personne qui peut saisir les parties et cela prends du temps.
Le plus simple serait de pouvoir mettre d'autres terminaux pour éditer les données et prendre les inscriptions.

Du coup, je cherche une méthode efficace pour cela.

Soit, je développe un client léger (en QML) qui communique avec le rcm principal
Soit RCM et le client léger lisent leurs données depuis une base (mais il me faut des notifications pour être sur d'etre à jour).
Soit intégrer un serveur web dans rcm, les clients légers sont des navigateurs mais comment être sur que les données sont à jours.
Soit RCM lit/enregistre ses données dans une base et je code un site web pour faire la même.

Quelle solution présente le plus d'avantages par rapport aux temps de dev.


Réponses

  • Salut,

    j'ai développé pour le boulot un logiciel de gestion documentaire. Les documents sont présentés dans des treeView et listView comme un explorateur de fichiers dans le logiciel client. Derrière, un serveur avec une base de données postgresql + notifications. Quand un client déplace un fichier, le renomme, le supprime, des notifications sont émises par le serveur postgresql et tous les clients remettent à jour le modèle.
    Tu peux rajouter à ça une connexion via websocket si tu veux transmettre des infos, valeurs temporaires qui n'auraient pas de raison d'être gérées en base de données.
  • J'ai commencé à modifier le code pour mettre ça en base de données postgresql.

    Il y a des trucs qui restent mystérieux.
    L'ajout fonctionne très bien pour un model mais pas pour un autre alors que les tables sont assez similaires.

    Autre solution, je pensais au nouveau système dans qt5. 11, qui permet d'envoyer des qobject à distance. Je me suis pas encore assez renseigner pour voir si ça fonctionne bien et si cela peu répondre à mon besoin (au moins partiellement)

    Merci pour la réponse, faut que je vois comment activer les notifications dans postgresql
  • Re,
    pour la notification postgresql, je te post ça dans la journée.
  • Tu as fait une mise à jour du modèle QSqlQueryModel (ou TableModel...) sur base des notifications ??
    Tu distingues les ajouts, les suppressions et les modifications ?
    ça m'intéresse d'un point du vue théorique cette histoire :)
  • ALors,

    pour installer un système de notification,
    1) créer un fichier watch.sql:

    -- Requires Postgres 9.4+

    -- Check if a row or table has been modifed.
    CREATE OR REPLACE FUNCTION if_modified_func() RETURNS TRIGGER AS $$
    DECLARE
    channel text;
    payload jsonb;
    rowdata jsonb;
    BEGIN
    IF TG_WHEN <> 'AFTER' THEN
    RAISE EXCEPTION 'if_modified_func() may only run as an AFTER trigger';
    END IF;

    -- Determine operation type
    IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN
    rowdata = row_to_json(OLD.*);
    ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
    rowdata = row_to_json(OLD.*);
    ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
    rowdata = row_to_json(NEW.*);
    ELSIF NOT (TG_LEVEL = 'STATEMENT' AND TG_OP IN ('INSERT','UPDATE','DELETE','TRUNCATE')) THEN
    RAISE EXCEPTION '[if_modified_func] - Trigger func added as trigger for unhandled case: %, %',TG_OP, TG_LEVEL;
    RETURN NULL;
    END IF;

    -- Construct JSON payload
    payload = jsonb_build_object('schema_name', TG_TABLE_SCHEMA::text,
    'table_name', TG_TABLE_NAME::text,
    'operation', TG_OP,
    'transaction_time', transaction_timestamp(),
    'capture_time', clock_timestamp(),
    'data', rowdata);

    channel = TG_ARGV[0];

    -- Notify to channel with serialized JSON payload.
    perform pg_notify(channel, payload::text);

    RETURN NULL;
    END;
    $$ LANGUAGE plpgsql;

    -- Create triggers that will execute on any change to the table.
    CREATE OR REPLACE FUNCTION watch_table(target_table regclass, channel text) RETURNS void AS $$
    DECLARE
    stmt text;
    BEGIN
    -- Drop existing triggers if they exist.
    EXECUTE unwatch_table(target_table);

    -- Row level watch trigger.
    stmt = 'CREATE TRIGGER watch_trigger_row AFTER INSERT OR UPDATE OR DELETE ON ' ||
    target_table || ' FOR EACH ROW EXECUTE PROCEDURE if_modified_func(' ||
    quote_literal(channel) || ');';
    RAISE NOTICE '%', stmt;
    EXECUTE stmt;

    -- Truncate level watch trigger. This will not contain any row data.
    stmt = 'CREATE TRIGGER watch_trigger_stmt AFTER TRUNCATE ON ' ||
    target_table || ' FOR EACH STATEMENT EXECUTE PROCEDURE if_modified_func(' ||
    quote_literal(channel) || ');';
    RAISE NOTICE '%', stmt;
    EXECUTE stmt;

    END;
    $$ LANGUAGE plpgsql;

    -- Unwatch a table.
    CREATE OR REPLACE FUNCTION unwatch_table(target_table regclass) RETURNS void AS $$
    BEGIN
    EXECUTE 'DROP TRIGGER IF EXISTS watch_trigger_row ON ' || target_table;
    EXECUTE 'DROP TRIGGER IF EXISTS watch_trigger_stmt ON ' || target_table;
    END;
    $$ LANGUAGE plpgsql;
    2) l'appliquer aux tables voulues :

    su postgres
    psql myDatabase

    In the Postgres shell:
    -- Create the functions
    \i watch.sql

    -- Watch the table and send notifications to channel 'changefeed'
    select watch_table('public.myTable', 'changefeed');
    3) ensuite en Qt souscrire aux notifications:

    QSqlDatabase db = QSqlDatabase::database();
    QSqlDriver *driver = db.driver();
    bool testNotify = driver->subscribeToNotification("changefeed");
    if (testNotify) {
    QObject::connect(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(&QSqlDriver::notification), [this, driver](const QString &, QSqlDriver::NotificationSource source, const QVariant & payload) {
    if (source == QSqlDriver::NotificationSource::OtherSource) {
    //do something
    }
    });
    }
    @ness : Dans l'application de gestion documentaire que j'ai codé, j'ai hérité 2 modèles, le premier de QAbstractItemModel et le 2ème de QAbstractListModel. Au démarrage, je lis la base de données et remplie mes modèles. Ensuite, si une autre instance de l'application est lancée sur un autre PC, alors les modifications apportées à la base de données sont notifiées aux autres instances, et les modèles sont mis à jour à l'aide du payload au format json qui décrit si c'est une insertion, deletion, ... et avec les données qu'il contient.
  • 10 Aug modifié
    Le payload json donne les détails sur la modif mais également le nom de la table qui a été modifier ? (EDIT: oui je viens de voir que tu définies les données du json).
    Je vais superviser plusieurs tables.
  • Ah ouais joli !

    Donc oui tu dois passer par le Abstract Model de base pour le remplir avec les données et puis gérer les ajouts, modifs qui sont directement dans la notification. Donc pas besoin de relancer une requête derrière. Top !

    Est-ce qu'on pourrait imaginer une classe modèle générique qui fait cela qq soit la Table ? Me semble bien...
    Vivement l'hiver que je puisse jouer avec tout ça (pour l'instant c'est entretient de la végétation à la maison :p)

    Merci
  • Perso, j’opterai pour une base !
Connectez-vous ou Inscrivez-vous pour répondre.