reader.js 7.3 KB

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