ObjectUtils.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. import configLoader from './Config'
  15. export type FileContent = {
  16. name: string,
  17. content: string,
  18. }
  19. class ObjectUtils {
  20. static notEmpty<T>(value: T | null | undefined): value is T {
  21. return value != null
  22. }
  23. static flatten(object: any, appendParentPath?: boolean, parent?: string): any {
  24. let result: any = {}
  25. Object.keys(object).forEach(k => {
  26. if (typeof object[k] === 'object' && !Array.isArray(object[k])) {
  27. if (object[k]) {
  28. result = {
  29. ...result,
  30. ...this.flatten(object[k], appendParentPath, k),
  31. }
  32. }
  33. } else {
  34. let key = k
  35. if (appendParentPath && parent) {
  36. key = `${parent}/${k}`
  37. }
  38. result[key] = object[k]
  39. }
  40. })
  41. if (Object.keys(result).length === 0) {
  42. return null
  43. }
  44. return result
  45. }
  46. static skipFields(object: any, fieldNames: string[]) {
  47. const result: any = {}
  48. if (Object.keys(object).length === 0) {
  49. return null
  50. }
  51. Object.keys(object).forEach(k => {
  52. if (!fieldNames.find(fn => fn === k)) {
  53. result[k] = object[k]
  54. }
  55. })
  56. if (Object.keys(result).length === 0) {
  57. return null
  58. }
  59. return result
  60. }
  61. static async wait(ms: number) {
  62. return new Promise<void>(r => { setTimeout(() => r(), ms) })
  63. }
  64. static async waitFor(predicate: () => boolean, timeoutMs: number = 15000, tryEvery: number = 1000) {
  65. const startTime = new Date().getTime()
  66. const testLoop = async () => {
  67. if (predicate()) {
  68. return
  69. }
  70. if (new Date().getTime() - startTime > timeoutMs) {
  71. throw new Error(`Timeout: waiting for more than ${timeoutMs} ms`)
  72. }
  73. await this.wait(tryEvery)
  74. await testLoop()
  75. }
  76. await testLoop()
  77. }
  78. static trim(fieldName: string, value: any): any {
  79. const isPassword = configLoader.config.passwordFields.find(p => p === fieldName)
  80. || fieldName.toLowerCase().indexOf('password') > -1
  81. return typeof value === 'string' && !isPassword ? value.trim() : value
  82. }
  83. static capitalizeFirstLetter(value: string): string {
  84. return value.charAt(0).toUpperCase() + value.slice(1)
  85. }
  86. static async retry(retryFunction: () => Promise<any>, retryEvery: number = 1000, retryCount: number = 3): Promise<any> {
  87. let currentTry = 0
  88. const retryLoop = async (): Promise<any> => {
  89. try {
  90. currentTry += 1
  91. if (currentTry > 1) {
  92. console.log('Retrying... ', currentTry)
  93. }
  94. const result = await retryFunction()
  95. return result
  96. } catch (err) {
  97. if (currentTry >= retryCount) {
  98. console.error(`Retry failed after ${retryCount} attempts.`)
  99. throw err
  100. }
  101. await this.wait(retryEvery)
  102. return retryLoop()
  103. }
  104. }
  105. return retryLoop()
  106. }
  107. }
  108. export default ObjectUtils