errors.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. const fs = require('fs');
  2. const csvParse = require('csv-parse/lib/sync');
  3. const { snakeToCamelCase } = require('../utils');
  4. const KNOWN_BASE_CLASSES = {
  5. 303: 'InvalidDCError',
  6. 400: 'BadRequestError',
  7. 401: 'UnauthorizedError',
  8. 403: 'ForbiddenError',
  9. 404: 'NotFoundError',
  10. 406: 'AuthKeyError',
  11. 420: 'FloodError',
  12. 500: 'ServerError',
  13. 503: 'TimedOutError',
  14. };
  15. /**
  16. * Gets the corresponding class name for the given error code,
  17. * this either being an integer (thus base error name) or str.
  18. */
  19. const getClassName = errorCode => {
  20. if (typeof errorCode === 'number') {
  21. return (
  22. KNOWN_BASE_CLASSES[Math.abs(errorCode)] ||
  23. 'RPCError' + errorCode.toString().replace('-', 'Neg')
  24. );
  25. }
  26. return snakeToCamelCase(
  27. errorCode
  28. .replace('FIRSTNAME', 'FIRST_NAME')
  29. .replace('SLOWMODE', 'SLOW_MODE')
  30. .toLowerCase(),
  31. 'Error'
  32. );
  33. };
  34. class TelegramError {
  35. constructor(codes, name, description) {
  36. // TODO Some errors have the same name but different integer codes
  37. // Should these be split into different files or doesn't really matter?
  38. // Telegram isn't exactly consistent with returned errors anyway.
  39. this.intCode = codes[0];
  40. this.stringCode = name;
  41. this.subclass = getClassName(codes[0]);
  42. this.subclassExists = Math.abs(codes[0]) in KNOWN_BASE_CLASSES;
  43. this.description = description;
  44. this.hasCaptures = name.includes('_X');
  45. if (this.hasCaptures) {
  46. this.name = getClassName(name.replace('_X', ''));
  47. this.pattern = name.replace('_X', '_(\\d+)');
  48. this.captureName = description.match(/{(\w+)}/)[1];
  49. } else {
  50. this.name = getClassName(name);
  51. this.pattern = name;
  52. this.captureName = null;
  53. }
  54. }
  55. }
  56. /**
  57. * Parses the input CSV file with columns (name, error codes, description)
  58. * and yields `Error` instances as a result.
  59. */
  60. const parseErrors = function*(csvFile) {
  61. const f = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(
  62. 1
  63. );
  64. for (let line = 0; line < f.length; line++) {
  65. if (f[line].length !== 3) {
  66. throw new Error(
  67. `Columns count mismatch, unquoted comma in desc? (line ${line +
  68. 2})`
  69. );
  70. }
  71. let [name, codes, description] = f[line];
  72. codes =
  73. codes === ''
  74. ? [400]
  75. : codes.split(' ').map(x => {
  76. if (isNaN(x)) {
  77. throw new Error(
  78. `Not all codes are integers (line ${line + 2})`
  79. );
  80. }
  81. return Number(x);
  82. });
  83. yield new TelegramError(codes, name, description);
  84. }
  85. };
  86. module.exports = {
  87. KNOWN_BASE_CLASSES,
  88. TelegramError,
  89. parseErrors,
  90. };