????

Your IP : 216.73.216.28


Current Path : C:/opt/pgsql/pgAdmin 4/runtime/src/js/
Upload File :
Current File : C:/opt/pgsql/pgAdmin 4/runtime/src/js/misc.js

/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////

const fs = require('fs');
const path = require('path');
const net = require('net');
const {platform, homedir} = require('os');
let pgadminServerProcess = null;
let pgAdminWindowObject = null;
let zoomInShortcut = null;
let zoomOutShortcut = null;
let actualSizeShortcut = null;
let toggleFullScreenShortcut = null;

// This function is used to check whether directory is present or not
// if not present then create it recursively
const createDir = (dirName) => {
  if (!fs.existsSync(dirName)) {
    fs.mkdirSync(dirName, {recursive: true});
  }
};

// This function is used to get the python executable path
// based on the platform. Use this for deployment.
const getPythonPath = () => {
  let pythonPath;
  switch (platform()) {
  case 'win32':
    pythonPath = '../python/python.exe';
    break;
  case 'darwin':
    pythonPath = '../../Frameworks/Python.framework/Versions/Current/bin/python3';
    break;
  case 'linux':
    pythonPath = '../venv/bin/python3';
    break;
  default:
    if (platform().startsWith('win')) {
      pythonPath = '../python/python.exe';
    } else {
      pythonPath = '../venv/bin/python3';
    }
  }

  return pythonPath;
};

// This function is used to get the [roaming] app data path
// based on the platform. Use this for config etc.
const getAppDataPath = () => {
  let appDataPath;
  switch (platform()) {
  case 'win32':
    appDataPath = path.join(process.env.APPDATA, 'pgadmin');
    break;
  case 'darwin':
    appDataPath = path.join(homedir(), 'Library', 'Preferences', 'pgadmin');
    break;
  case 'linux':
    if ('XDG_CONFIG_HOME' in process.env) {
      appDataPath = path.join(process.env.XDG_CONFIG_HOME, 'pgadmin');
    } else {
      appDataPath = path.join(homedir(), '.config', 'pgadmin');
    }
    break;
  default:
    if (platform().startsWith('win')) {
      appDataPath = path.join(process.env.APPDATA, 'pgadmin');
    } else if ('XDG_CONFIG_HOME' in process.env) {
      appDataPath = path.join(process.env.XDG_CONFIG_HOME, 'pgadmin');
    } else {
      appDataPath = path.join(homedir(), '.config', 'pgadmin');
    }
  }

  // Create directory if not exists
  createDir(appDataPath);

  return appDataPath;
};

// This function is used to get the [local] app data path
// based on the platform. Use this for logs etc.
const getLocalAppDataPath = () => {
  let localAppDataPath;
  switch (platform()) {
  case 'win32':
    localAppDataPath = path.join(process.env.LOCALAPPDATA, 'pgadmin');
    break;
  case 'darwin':
    localAppDataPath = path.join(homedir(), 'Library', 'Application Support', 'pgadmin');
    break;
  case 'linux':
    if ('XDG_DATA_HOME' in process.env) {
      localAppDataPath = path.join(process.env.XDG_DATA_HOME, 'pgadmin');
    } else {
      localAppDataPath = path.join(homedir(), '.local', 'share', 'pgadmin');
    }
    break;
  default:
    if (platform().startsWith('win')) {
      localAppDataPath = path.join(process.env.LOCALAPPDATA, 'pgadmin');
    } else if ('XDG_DATA_HOME' in process.env) {
      localAppDataPath = path.join(process.env.XDG_DATA_HOME, 'pgadmin');
    } else {
      localAppDataPath = path.join(homedir(), '.local', 'share', 'pgadmin');
    }
  }

  // Create directory if not exists
  createDir(localAppDataPath);

  return localAppDataPath;
};

// This function is used to get the random available TCP port
// if fixedPort is set to 0. Else check whether port is in used or not.
const getAvailablePort = (fixedPort) => {
  return new Promise(function(resolve, reject) {
    const server = net.createServer();

    server.listen(fixedPort, '127.0.0.1');

    server.on('error', (e) => {
      reject(e.code);
    });

    server.on('listening', () => {
      let serverPort = server.address().port;
      server.close();
      resolve(serverPort);
    });
  });
};

// Get the app data folder path
const currentTime = (new Date()).getTime();
const serverLogFile = path.join(getLocalAppDataPath(), 'pgadmin4.' + currentTime.toString() + '.log');
const configFileName = path.join(getAppDataPath(), 'runtime_config.json');
const DEFAULT_CONFIG_DATA = {'fixedPort': false, 'portNo': 5050, 'connectionTimeout': 90, 'zoomLevel': 0, 'openDocsInBrowser': true};

// This function is used to read the file and return the content
const readServerLog = () => {
  let data = null;

  if (fs.existsSync(serverLogFile)) {
    data = fs.readFileSync(serverLogFile, 'utf8');
  } else {
    let errMsg = 'Unable to read file ' + serverLogFile + '.';
    console.warn(errMsg);
    return errMsg;
  }

  return data;
};

// This function is used to write the data into the log file
const writeServerLog = (data) => {
  data = data + '\n';
  if (fs.existsSync(serverLogFile)) {
    fs.writeFileSync(serverLogFile, data, {flag: 'a+'});
  } else {
    fs.writeFileSync(serverLogFile, data, {flag: 'w'});
  }
};

// This function is used to remove the log file
const removeLogFile = () => {
  if (fs.existsSync(serverLogFile)) {
    fs.rmSync(serverLogFile);
  }
};

// This function used to set the object of pgAdmin server process.
const setProcessObject = (processObject) => {
  pgadminServerProcess = processObject;
};

// This function used to set the object of pgAdmin window.
const setPgAdminWindowObject = (windowObject) => {
  pgAdminWindowObject = windowObject;
};

// This function is used to get the server log file.
const getServerLogFile = () => {
  return serverLogFile;
};

// This function is used to get the runtime config file.
const getRunTimeConfigFile = () => {
  return configFileName;
};

// This function is used to kill the server process, remove the log files
// and quit the application.
const cleanupAndQuitApp = () => {
  // Remove the server log file on exit
  removeLogFile();

  // Killing pgAdmin4 server process if application quits
  if (pgadminServerProcess != null) {
    try {
      process.kill(pgadminServerProcess.pid);
    }
    catch (e) {
      console.warn('Failed to kill server process.');
    }
  }

  if (pgAdminWindowObject != null) {
    // Remove all the cookies.
    pgAdminWindowObject.cookies.getAll({}, function(cookies) {
      try {
        cookies.forEach(function(cookie) {
          pgAdminWindowObject.cookies.remove({url: 'http://' + cookie.domain, name: cookie.name});
        });
      } catch (error) {
        console.warn('Failed to remove cookies.');
      } finally {
        pgAdminWindowObject = null;
        // Quit Application
        nw.App.quit();
      }
    });
  } else {
    // Quit Application
    nw.App.quit();
  }
};

// This function is used to create zoom events based on platform
const setZoomEvents = () => {
  if (platform() == 'darwin') {
    zoomInShortcut = new nw.Shortcut({key: 'Command+Equal'});
    zoomOutShortcut = new nw.Shortcut({key: 'Command+Minus'});
    actualSizeShortcut = new nw.Shortcut({key: 'Command+0'});
    toggleFullScreenShortcut = new nw.Shortcut({key: 'Command+Ctrl+F'});
  } else {
    zoomInShortcut = new nw.Shortcut({key: 'Ctrl+Equal'});
    zoomOutShortcut = new nw.Shortcut({key: 'Ctrl+Minus'});
    actualSizeShortcut = new nw.Shortcut({key: 'Ctrl+0'});
    // Use F10 instead of F11. F11 does not work possibly due to Chromium reserving it for their function.
    toggleFullScreenShortcut = new nw.Shortcut({key: 'F10'});
  }

  zoomInShortcut.on('active', function() {
    zoomIn();
  });

  zoomOutShortcut.on('active', function() {
    zoomOut();
  });

  actualSizeShortcut.on('active', function() {
    actualSize();
  });

  toggleFullScreenShortcut.on('active', function() {
    toggleFullScreen();
  });

  zoomInShortcut.on('failed', function(msg) {
    let errMsg = 'Failed to register zoom in shortcut with error: ' + msg;
    console.warn(errMsg);
  });

  zoomOutShortcut.on('failed', function(msg) {
    let errMsg = 'Failed to register zoom out shortcut with error: ' + msg;
    console.warn(errMsg);
  });

  actualSizeShortcut.on('failed', function(msg) {
    let errMsg = 'Failed to register actual size shortcut with error: ' + msg;
    console.warn(errMsg);
  });

  toggleFullScreenShortcut.on('failed', function(msg) {
    let errMsg = 'Failed to register toggle full screen shortcut with error: ' + msg;
    console.warn(errMsg);
  });
};

// This function is used to iterate all open windows and set the zoom level.
const setZoomLevelForAllWindows = () => {
  nw.Window.getAll(function(winArray) {
    for (let arr_val of winArray) {
      arr_val.zoomLevel = pgAdminWindowObject.zoomLevel;
    }
  });
};

// This function used to zoom in the pgAdmin window.
const zoomIn = () => {
  if (pgAdminWindowObject != null) {
    pgAdminWindowObject.zoomLevel += 0.5;
    setZoomLevelForAllWindows();
    ConfigureStore.set('zoomLevel', pgAdminWindowObject.zoomLevel);
    ConfigureStore.saveConfig();
  }
};

// This function used to zoom out the pgAdmin window.
const zoomOut = () => {
  if (pgAdminWindowObject != null) {
    pgAdminWindowObject.zoomLevel -= 0.5;
    setZoomLevelForAllWindows();
    ConfigureStore.set('zoomLevel', pgAdminWindowObject.zoomLevel);
    ConfigureStore.saveConfig();
  }
};

// This function used to reset the zoom level of pgAdmin window.
const actualSize = () => {
  if (pgAdminWindowObject != null) {
    pgAdminWindowObject.zoomLevel = 0;
    setZoomLevelForAllWindows();
    ConfigureStore.set('zoomLevel', pgAdminWindowObject.zoomLevel);
    ConfigureStore.saveConfig();
  }
};

const toggleFullScreen = () => {
  if (pgAdminWindowObject != null) {
    // Toggle full screen
    pgAdminWindowObject.toggleFullscreen();

    // Change the menu label.
    let menu_label = pgAdminWindowObject.window.document.querySelector('#mnu_toggle_fullscreen_runtime span').innerHTML;
    if (menu_label.indexOf('Enter Full Screen') >= 0) {
      pgAdminWindowObject.window.document.querySelector('#mnu_toggle_fullscreen_runtime span').innerHTML = menu_label.replace('Enter', 'Exit');
    } else if (menu_label.indexOf('Exit Full Screen') >= 0) {
      pgAdminWindowObject.window.document.querySelector('#mnu_toggle_fullscreen_runtime span').innerHTML = menu_label.replace('Exit', 'Enter');
    }
  }
};

// This function is used to register zoom events.
const registerZoomEvents = () => {
  nw.App.registerGlobalHotKey(zoomInShortcut);
  nw.App.registerGlobalHotKey(zoomOutShortcut);
  nw.App.registerGlobalHotKey(actualSizeShortcut);
  nw.App.registerGlobalHotKey(toggleFullScreenShortcut);
};

// This function is used to unregister zoom events.
const unregisterZoomEvents = () => {
  nw.App.unregisterGlobalHotKey(zoomInShortcut);
  nw.App.unregisterGlobalHotKey(zoomOutShortcut);
  nw.App.unregisterGlobalHotKey(actualSizeShortcut);
  nw.App.unregisterGlobalHotKey(toggleFullScreenShortcut);
};

let ConfigureStore = {
  fileName: configFileName,
  jsonData: {},

  init: function() {
    if (!this.readConfig()){
      this.jsonData = DEFAULT_CONFIG_DATA;
      this.saveConfig();
    }
  },

  // This function is used to write configuration data
  saveConfig: function() {
    fs.writeFileSync(this.fileName, JSON.stringify(this.jsonData, null, 4), {flag: 'w'});
  },

  // This function is used to read the configuration data
  readConfig: function() {
    if (fs.existsSync(this.fileName)) {
      try {
        this.jsonData = JSON.parse(fs.readFileSync(this.fileName));
      } catch (error) {
        /* If the file is not present or invalid JSON data in file */
        this.jsonData = {};
      }
    } else {
      let errMsg = 'Unable to read file ' + this.fileName + ' not found.';
      console.warn(errMsg);
      return false;
    }

    return true;
  },

  getConfigData: function() {
    return this.jsonData;
  },

  get: function(key, if_not_value) {
    if(this.jsonData[key] !== undefined) {
      return this.jsonData[key];
    } else {
      return if_not_value;
    }
  },

  set: function(key, value) {
    if(typeof key === 'object'){
      this.jsonData = {
        ...this.jsonData,
        ...key,
      };
    } else if(value === '' || value == null || typeof(value) == 'undefined') {
      if(this.jsonData[key] !== undefined) {
        delete this.jsonData[key];
      }
    } else {
      this.jsonData[key] = value;
    }
  },
};

function parseConsoleArgs(_method, args) {
  const retData = Array.from(args).map(arg => {
    try {
      if(arg.stack) return arg.stack;
      return JSON.stringify(arg);
    } catch (e) {
      return arg
    }
  });
  return retData?.join(' ');
}


module.exports = {
  readServerLog: readServerLog,
  writeServerLog: writeServerLog,
  getAvailablePort: getAvailablePort,
  getPythonPath: getPythonPath,
  setProcessObject: setProcessObject,
  cleanupAndQuitApp: cleanupAndQuitApp,
  getServerLogFile: getServerLogFile,
  getRunTimeConfigFile: getRunTimeConfigFile,
  setPgAdminWindowObject: setPgAdminWindowObject,
  zoomIn: zoomIn,
  zoomOut: zoomOut,
  actualSize: actualSize,
  toggleFullScreen: toggleFullScreen,
  setZoomEvents: setZoomEvents,
  registerZoomEvents: registerZoomEvents,
  unregisterZoomEvents: unregisterZoomEvents,
  setZoomLevelForAllWindows: setZoomLevelForAllWindows,
  ConfigureStore: ConfigureStore,
  parseConsoleArgs: parseConsoleArgs,
};