reader.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import axios from 'axios';
  2. import * as utils from '../share/utils';
  3. import * as cryptoUtils from '../share/cryptoUtils';
  4. import wsc from './webSocketConnection';
  5. const api = axios.create({
  6. baseURL: '/api/reader'
  7. });
  8. /*const workerApi = axios.create({
  9. baseURL: '/api/worker'
  10. });*/
  11. class Reader {
  12. constructor() {
  13. }
  14. async getWorkerStateFinish(workerId, callback) {
  15. if (!callback) callback = () => {};
  16. let response = {};
  17. const requestId = await wsc.send({action: 'worker-get-state-finish', workerId});
  18. let prevResponse = false;
  19. while (1) {// eslint-disable-line no-constant-condition
  20. response = await wsc.message(requestId);
  21. if (!response.state && prevResponse !== false) {//экономия траффика
  22. callback(prevResponse);
  23. } else {//были изменения worker state
  24. if (!response.state)
  25. throw new Error('Неверный ответ api');
  26. callback(response);
  27. prevResponse = response;
  28. }
  29. if (response.state == 'finish' || response.state == 'error') {
  30. break;
  31. }
  32. }
  33. return response;
  34. }
  35. async loadBook(opts, callback) {
  36. if (!callback) callback = () => {};
  37. let response = await wsc.message(await wsc.send(Object.assign({action: 'load-book'}, opts)));
  38. const workerId = response.workerId;
  39. if (!workerId)
  40. throw new Error('Неверный ответ api');
  41. callback({totalSteps: 4});
  42. callback(response);
  43. response = await this.getWorkerStateFinish(workerId, callback);
  44. if (response) {
  45. if (response.state == 'finish') {//воркер закончил работу, можно скачивать кешированный на сервере файл
  46. callback({step: 4});
  47. const book = await this.loadCachedBook(response.path, callback, response.size);
  48. return Object.assign({}, response, {data: book.data});
  49. }
  50. if (response.state == 'error') {
  51. let errMes = response.error;
  52. if (errMes.indexOf('getaddrinfo') >= 0 ||
  53. errMes.indexOf('ECONNRESET') >= 0 ||
  54. errMes.indexOf('EINVAL') >= 0 ||
  55. errMes.indexOf('404') >= 0)
  56. errMes = `Ресурс не найден по адресу: ${response.url}`;
  57. throw new Error(errMes);
  58. }
  59. } else {
  60. throw new Error('Пустой ответ сервера');
  61. }
  62. }
  63. async checkCachedBook(url) {
  64. let estSize = -1;
  65. try {
  66. const response = await axios.head(url, {headers: {'Cache-Control': 'no-cache'}});
  67. if (response.headers['content-length']) {
  68. estSize = response.headers['content-length'];
  69. }
  70. } catch (e) {
  71. //
  72. }
  73. return estSize;
  74. }
  75. async loadCachedBook(url, callback, estSize = -1) {
  76. if (!callback) callback = () => {};
  77. callback({state: 'loading', progress: 0});
  78. //получение размера файла
  79. if (estSize && estSize < 0) {
  80. estSize = await this.checkCachedBook(url);
  81. }
  82. //получение файла
  83. estSize = (estSize > 0 ? estSize : 1000000);
  84. const options = {
  85. onDownloadProgress: (progress) => {
  86. while (progress.loaded > estSize) estSize *= 1.5;
  87. if (callback)
  88. callback({progress: Math.round((progress.loaded*100)/estSize)});
  89. }
  90. }
  91. return await axios.get(url, options);
  92. }
  93. async uploadFile(file, maxUploadFileSize = 10*1024*1024, callback) {
  94. if (file.size > maxUploadFileSize)
  95. throw new Error(`Размер файла превышает ${maxUploadFileSize} байт`);
  96. let formData = new FormData();
  97. formData.append('file', file, file.name);
  98. const options = {
  99. headers: {
  100. 'Content-Type': 'multipart/form-data'
  101. },
  102. onUploadProgress: progress => {
  103. const total = (progress.total ? progress.total : progress.loaded + 200000);
  104. if (callback)
  105. callback({state: 'upload', progress: Math.round((progress.loaded*100)/total)});
  106. }
  107. };
  108. let response = await api.post('/upload-file', formData, options);
  109. if (response.data.state == 'error')
  110. throw new Error(response.data.error);
  111. const url = response.data.url;
  112. if (!url)
  113. throw new Error('Неверный ответ api');
  114. return url;
  115. }
  116. async storage(request) {
  117. const response = await wsc.message(await wsc.send({action: 'reader-storage', body: request}));
  118. if (response.error)
  119. throw new Error(response.error);
  120. if (!response.state)
  121. throw new Error('Неверный ответ api');
  122. return response;
  123. }
  124. makeUrlFromBuf(buf) {
  125. const key = utils.toHex(cryptoUtils.sha256(buf));
  126. return `disk://${key}`;
  127. }
  128. async uploadFileBuf(buf, url) {
  129. if (!url)
  130. url = this.makeUrlFromBuf(buf);
  131. let response;
  132. try {
  133. await axios.head(url.replace('disk://', '/upload/'), {headers: {'Cache-Control': 'no-cache'}});
  134. response = await wsc.message(await wsc.send({action: 'upload-file-touch', url}));
  135. } catch (e) {
  136. response = await wsc.message(await wsc.send({action: 'upload-file-buf', buf}));
  137. }
  138. if (response.error)
  139. throw new Error(response.error);
  140. return response;
  141. }
  142. async getUploadedFileBuf(url) {
  143. url = url.replace('disk://', '/upload/');
  144. return (await axios.get(url)).data;
  145. }
  146. async checkBuc(bookUrls) {
  147. const response = await wsc.message(await wsc.send({action: 'check-buc', bookUrls}));
  148. if (response.error)
  149. throw new Error(response.error);
  150. if (!response.data)
  151. throw new Error(`response.data is empty`);
  152. return response.data;
  153. }
  154. }
  155. export default new Reader();