show_buffer.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/env node
  2. // @ts-check
  3. const { rclientHistory: rclient } = require('../lib/redis')
  4. const { keySchema } = require('../lib/chunk_store/redis')
  5. const commandLineArgs = require('command-line-args')
  6. const optionDefinitions = [
  7. { name: 'historyId', type: String, defaultOption: true },
  8. ]
  9. // Column width for key display alignment; can be overridden with COL_WIDTH env variable
  10. const COLUMN_WIDTH = process.env.COL_WIDTH
  11. ? parseInt(process.env.COL_WIDTH, 10)
  12. : 45
  13. let options
  14. try {
  15. options = commandLineArgs(optionDefinitions)
  16. } catch (e) {
  17. console.error(
  18. 'Error parsing command line arguments:',
  19. e instanceof Error ? e.message : String(e)
  20. )
  21. console.error('Usage: ./show_buffer.js <historyId>')
  22. process.exit(1)
  23. }
  24. const { historyId } = options
  25. if (!historyId) {
  26. console.error('Usage: ./show_buffer.js <historyId>')
  27. process.exit(1)
  28. }
  29. function format(str, indent = COLUMN_WIDTH + 2) {
  30. const lines = str.split('\n')
  31. for (let i = 1; i < lines.length; i++) {
  32. lines[i] = ' '.repeat(indent) + lines[i]
  33. }
  34. return lines.join('\n')
  35. }
  36. async function displayKeyValue(
  37. rclient,
  38. key,
  39. { parseJson = false, formatDate = false } = {}
  40. ) {
  41. const value = await rclient.get(key)
  42. let displayValue = '(nil)'
  43. if (value) {
  44. if (parseJson) {
  45. try {
  46. displayValue = format(JSON.stringify(JSON.parse(value), null, 2))
  47. } catch (e) {
  48. displayValue = ` Raw value: ${value}`
  49. }
  50. } else if (formatDate) {
  51. const ts = parseInt(value, 10)
  52. displayValue = `${new Date(ts).toISOString()} (${value})`
  53. } else {
  54. displayValue = value
  55. }
  56. }
  57. console.log(`${key.padStart(COLUMN_WIDTH)}: ${displayValue}`)
  58. }
  59. async function displayBuffer(projectId) {
  60. console.log(`Buffer for history ID: ${projectId}`)
  61. console.log('--------------------------------------------------')
  62. try {
  63. const headKey = keySchema.head({ projectId })
  64. const headVersionKey = keySchema.headVersion({ projectId })
  65. const persistedVersionKey = keySchema.persistedVersion({ projectId })
  66. const expireTimeKey = keySchema.expireTime({ projectId })
  67. const persistTimeKey = keySchema.persistTime({ projectId })
  68. const changesKey = keySchema.changes({ projectId })
  69. await displayKeyValue(rclient, headKey, { parseJson: true })
  70. await displayKeyValue(rclient, headVersionKey)
  71. await displayKeyValue(rclient, persistedVersionKey)
  72. await displayKeyValue(rclient, expireTimeKey, { formatDate: true })
  73. await displayKeyValue(rclient, persistTimeKey, { formatDate: true })
  74. const changesList = await rclient.lrange(changesKey, 0, -1)
  75. // 6. changes
  76. let changesListDisplay = '(nil)'
  77. if (changesList) {
  78. changesListDisplay = changesList.length
  79. ? format(
  80. changesList
  81. .map((change, index) => `[${index}]: ${change}`)
  82. .join('\n')
  83. )
  84. : '(empty list)'
  85. }
  86. console.log(`${changesKey.padStart(COLUMN_WIDTH)}: ${changesListDisplay}`)
  87. } catch (error) {
  88. console.error('Error fetching data from Redis:', error)
  89. throw error
  90. }
  91. }
  92. ;(async () => {
  93. let errorOccurred = false
  94. try {
  95. await displayBuffer(historyId)
  96. } catch (error) {
  97. errorOccurred = true
  98. } finally {
  99. rclient.quit(() => {
  100. process.exit(errorOccurred ? 1 : 0)
  101. })
  102. }
  103. })()