diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js index 2daf9df23..486ec147e 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js @@ -227,6 +227,9 @@ define('pgadmin.node.server', [ } t.unload(i); } + pgBrowser.Events.trigger( + 'pgadmin:server:disconnect', {item: i, data: d}, false + ); }}) .fail(function(xhr, status, error) { Notify.pgRespErrorNotify(xhr, error); diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index be4fa79c9..009ab496e 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -15,7 +15,7 @@ import Notify, {initializeModalProvider, initializeNotifier} from '../../../stat import { checkMasterPassword } from '../../../static/js/Dialogs/index'; import { pgHandleItemError } from '../../../static/js/utils'; import { Search } from './quick_search/trigger_search'; -import { send_heartbeat } from './heartbeat'; +import { send_heartbeat, stop_heartbeat } from './heartbeat'; define('pgadmin.browser', [ 'sources/gettext', 'sources/url_for', 'require', 'jquery', @@ -586,6 +586,10 @@ define('pgadmin.browser', [ 'pgadmin:server:connected', send_heartbeat.bind(obj) ); + obj.Events.on( + 'pgadmin:server:disconnect', stop_heartbeat.bind(obj) + ); + obj.set_master_password(''); obj.check_corrupted_db_file(); obj.Events.on('pgadmin:browser:tree:add', obj.onAddTreeNode.bind(obj)); diff --git a/web/pgadmin/browser/static/js/heartbeat.js b/web/pgadmin/browser/static/js/heartbeat.js index 496328014..c526a310f 100644 --- a/web/pgadmin/browser/static/js/heartbeat.js +++ b/web/pgadmin/browser/static/js/heartbeat.js @@ -16,16 +16,32 @@ import pgAdmin from 'sources/pgadmin'; const axiosApi = getApiInstance(); let HEARTBEAT_TIMEOUT = pgAdmin.heartbeat_timeout * 1000; -export function send_heartbeat(_server_id) { +export function send_heartbeat(_server_id, _item) { + // Send heartbeat to the server every 30 seconds - setInterval(function() { - axiosApi.post(url_for('misc.heartbeat'), {'sid': _server_id}) - .then(() => { - // pass + _item.heartbeat = setInterval(function() { + axiosApi.post(url_for('misc.log_heartbeat'), {'sid': _server_id}) + .then((data) => { + if (data.status !== 200) { + stop_heartbeat(_item); + } }) .catch((error) => { - Notifier.error(gettext(`pgAdmin server not responding, try to login again: ${error.message || error.response.data.errormsg}`)); + if (error && error.message == 'Network Error') { + Notifier.error(gettext(`pgAdmin server not responding, try to login again: ${error.message || error.response.data.errormsg}`)); + } else { + Notifier.error(gettext(`Server heartbeat logging error: ${error.message || error.response.data.errormsg}`)); + } + stop_heartbeat(_item); }); }, HEARTBEAT_TIMEOUT); } + + +export function stop_heartbeat(_obj) { + let _item = _obj.item || _obj, + _id = _item.getMetadata('data')._id; + clearInterval(_item.heartbeat); + axiosApi.post(url_for('misc.stop_heartbeat'), {'sid': _id}); +} diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index 0554d0d14..87061006c 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -19,7 +19,8 @@ from pgadmin.utils.session import cleanup_session_files from pgadmin.misc.themes import get_all_themes from pgadmin.utils.constants import MIMETYPE_APP_JS, UTILITIES_ARRAY from pgadmin.utils.ajax import precondition_required, make_json_response -from pgadmin.utils.heartbeat import log_server_heartbeat, get_server_heartbeat +from pgadmin.utils.heartbeat import log_server_heartbeat,\ + get_server_heartbeat, stop_server_heartbeat import config import subprocess import os @@ -94,8 +95,8 @@ class MiscModule(PgAdminModule): list: a list of url endpoints exposed to the client. """ return ['misc.ping', 'misc.index', 'misc.cleanup', - 'misc.validate_binary_path', 'misc.heartbeat', - 'misc.get_heartbeat'] + 'misc.validate_binary_path', 'misc.log_heartbeat', + 'misc.stop_heartbeat', 'misc.get_heartbeat'] def register(self, app, options): """ @@ -158,9 +159,9 @@ def cleanup(): return "" -@blueprint.route("/heartbeat", methods=['POST']) +@blueprint.route("/heartbeat/log", methods=['POST']) @pgCSRFProtect.exempt -def heartbeat(): +def log_heartbeat(): data = None if hasattr(request.data, 'decode'): data = request.data.decode('utf-8') @@ -168,8 +169,25 @@ def heartbeat(): if data != '': data = json.loads(data) - log_server_heartbeat(data) - return make_json_response(data=gettext('Heartbeat logged successfully.'), + status, msg = log_server_heartbeat(data) + if status: + return make_json_response(data=msg, status=200) + else: + return make_json_response(data=msg, status=404) + + +@blueprint.route("/heartbeat/stop", methods=['POST']) +@pgCSRFProtect.exempt +def stop_heartbeat(): + data = None + if hasattr(request.data, 'decode'): + data = request.data.decode('utf-8') + + if data != '': + data = json.loads(data) + + status, msg = stop_server_heartbeat(data) + return make_json_response(data=msg, status=200) diff --git a/web/pgadmin/utils/heartbeat.py b/web/pgadmin/utils/heartbeat.py index 8a0ae730f..3ec430b83 100644 --- a/web/pgadmin/utils/heartbeat.py +++ b/web/pgadmin/utils/heartbeat.py @@ -14,6 +14,7 @@ import threading import datetime import config from flask import session, current_app +from flask_babel import gettext def log_server_heartbeat(data): @@ -28,16 +29,37 @@ def log_server_heartbeat(data): if session.sid not in _server_heartbeat: _server_heartbeat[session.sid] = {} - _server_heartbeat[session.sid][data['sid']] = { - 'timestamp': datetime.datetime.now(), - 'conn': manager.connections - } + if not manager: + stop_server_heartbeat(data) + return False, gettext("Manager not found. Stopped Heartbeat logging.") + else: + _server_heartbeat[session.sid][data['sid']] = { + 'timestamp': datetime.datetime.now(), + 'conn': manager.connections + } + current_app.logger.debug( + "Heartbeat logged for the session id##server id: {0}##{1}".format( + session.sid, data['sid'])) - setattr(current_app, '_pgadmin_server_heartbeat', _server_heartbeat) + setattr(current_app, '_pgadmin_server_heartbeat', _server_heartbeat) + return True, gettext("Heartbeat logged successfully.") - current_app.logger.debug( - "Heartbeat logged for the session id##server id: {0}##{1}".format( - session.sid, data['sid'])) + +def stop_server_heartbeat(data): + """Stop logging server heartbeat.""" + _server_heartbeat = getattr(current_app, '_pgadmin_server_heartbeat', {}) + + if session.sid in _server_heartbeat and \ + data['sid'] in _server_heartbeat[session.sid]: + _server_heartbeat[session.sid].pop(data['sid']) + + current_app.logger.debug( + "Heartbeat logging stopped for the session" + " id##server id: {0}##{1}".format(session.sid, data['sid'])) + + setattr(current_app, '_pgadmin_server_heartbeat', _server_heartbeat) + + return True, gettext("Stopped Heartbeat logging.") def get_server_heartbeat(server_id):