Internet Cache.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. #define COMPARE ComparePathCI
  5. namespace EE{
  6. /******************************************************************************/
  7. static Str EatWWW(Str url) // convert "http://www.esenthel.com" -> "http://esenthel.com"
  8. {
  9. Bool http = StartsPath(url, "http://" ) ; if(http )url.remove(0, 7);
  10. Bool https=(!http && StartsPath(url, "https://")); if(https)url.remove(0, 8);
  11. if(Starts(url, "www."))url.remove(0, 4);
  12. if(https)url.insert(0, "https://");
  13. if(http )url.insert(0, "http://" );
  14. return url;
  15. }
  16. static Str ShortName(Str url) // convert "http://www.esenthel.com" -> "esenthel.com"
  17. {
  18. if(StartsPath(url, "http://" ))url.remove(0, 7);else
  19. if(StartsPath(url, "https://"))url.remove(0, 8);
  20. if(Starts (url, "www." ))url.remove(0, 4);
  21. return url;
  22. }
  23. static void ImportImageFunc(InternetCache::ImportImage &ii, InternetCache &ic, Int thread_index=0)
  24. {
  25. File *src=null, temp;
  26. if(ii.pf){if(temp.readTry(*ii.pf, ic._pak))src=&temp;}else
  27. if(ii.ds)src=ii.ds->open(temp);
  28. if(src)
  29. {
  30. src->pos(0);
  31. ThreadMayUseGPUData();
  32. ii.image_temp.ImportTry(*src, -1, IMAGE_2D, ic._image_mip_maps);
  33. ThreadFinishedUsingGPUData();
  34. }
  35. if(src)src->pos(0); // reset position after loading
  36. ii.done=true; // !! don't do anything after this step because the object can get removed !!
  37. }
  38. static void ICUpdate(InternetCache &ic) {ic.update();}
  39. /******************************************************************************/
  40. void InternetCache::flush()
  41. {
  42. if(_downloaded.elms() && _pak.pakFileName().is()) // we want to save data
  43. {
  44. if(_threads)REPA(_import_images)_threads->wait(_import_images[i], ImportImageFunc, T); // wait until the worker threads finish processing the importing, as they operate on Pak which we're about to update
  45. Str name=_pak.pakFileName(); Cipher *cipher=_pak._file_cipher; // copy in case load/update will delete this
  46. _pak.load(name, cipher); // reload the pak in case it was modified by another app/instance, in which case the 'PakUpdate' would make the file corrupt with out-dated info
  47. PakUpdate(_pak, SCAST(Memb<PakFileData>, _downloaded), name, cipher, _compress);
  48. _downloaded.del();
  49. }
  50. }
  51. void InternetCache::del()
  52. {
  53. App._callbacks.exclude(ICUpdate, T);
  54. REPAO(_downloading).del();
  55. if(_threads)REPA(_import_images)_threads->cancel(_import_images[i], ImportImageFunc, T); // cancel importing
  56. flush();
  57. if(_threads)
  58. {
  59. REPA(_import_images)_threads->wait(_import_images[i], ImportImageFunc, T);
  60. _threads=null;
  61. }
  62. _downloaded .del();
  63. _import_images.del();
  64. _to_download .del();
  65. _verified .del();
  66. _to_verify .del();
  67. _pak .del();
  68. }
  69. void InternetCache::create(C Str &db_name, Threads *threads, Cipher *cipher, COMPRESS_TYPE compress, Int image_mip_maps)
  70. {
  71. del();
  72. if(D.canUseGPUDataOnSecondaryThread())_threads=threads; // setup worker threads only if we can operate on GPU on secondary threads
  73. _compress =compress;
  74. _image_mip_maps=image_mip_maps;
  75. if(db_name.is())if(!_pak.load(db_name, cipher))
  76. {
  77. Mems<PakFileData> pfd; _pak.create(pfd, db_name, 0, cipher); // create an empty pak
  78. }
  79. }
  80. /******************************************************************************/
  81. void InternetCache::changed(C Str &url)
  82. {
  83. if(url.is())
  84. {
  85. Str name=ShortName(url); if(name.is())
  86. {
  87. Str slim=EatWWW(url);
  88. _verified.binaryExclude(slim, COMPARE);
  89. REPA(_downloading)if(EqualPath(_downloading[i].url(), slim))
  90. {
  91. _downloading[i].del();
  92. _to_download.binaryInclude(slim, COMPARE); enable(); // restart the download
  93. return;
  94. }
  95. if(_to_verify .binaryHas(slim, COMPARE))return; // it will be checked
  96. if(_to_download.binaryHas(slim, COMPARE))return; // it will be downloaded
  97. if(ImagePtr().find(slim)) // download if currently referenced
  98. {
  99. _to_download.binaryInclude(slim, COMPARE); enable();
  100. }
  101. }
  102. }
  103. }
  104. Bool InternetCache::getFile(C Str &url, SrcFile &file)
  105. {
  106. file.clear();
  107. if(!url.is())return true;
  108. Str name=ShortName(url); if(!name.is())return false;
  109. Str slim= EatWWW(url);
  110. if(file.pf=_pak.find(name, false))
  111. {
  112. // if file was cached, then check if it was verified
  113. if(_verified .binaryHas (slim, COMPARE))return true;
  114. if(_to_download.binaryHas (slim, COMPARE))return true;
  115. REPA(_downloading)if(EqualPath (_downloading[i].url(), slim))return true;
  116. if(_to_verify .binaryInclude(slim, COMPARE))enable(); // verify
  117. return true;
  118. }
  119. REPA(_downloaded )if(EqualPath (_downloaded [i].name , name)){file.ds=&_downloaded[i].data; return true;}
  120. REPA(_downloading)if(EqualPath (_downloading[i].url(), slim))return false;
  121. if(_to_download.binaryInclude(slim, COMPARE))enable();
  122. return false;
  123. }
  124. ImagePtr InternetCache::getImage(C Str &url)
  125. {
  126. ImagePtr img; if(url.is())
  127. {
  128. Str slim=EatWWW(url); if(slim.is())if(!img.find(slim))
  129. {
  130. CACHE_MODE mode=Images.mode(CACHE_DUMMY); img=slim;
  131. Images.mode(mode );
  132. SrcFile file; if(getFile(url, file))
  133. {
  134. ImportImage &ii=_import_images.New();
  135. Swap<SrcFile>(ii, file);
  136. ii.image_ptr=img;
  137. import(ii);
  138. enable();
  139. }
  140. }
  141. }
  142. return img;
  143. }
  144. /******************************************************************************/
  145. void InternetCache::import(ImportImage &ii)
  146. {
  147. if(_threads)_threads->queue(ii, ImportImageFunc, T);else ImportImageFunc(ii, T);
  148. }
  149. Bool InternetCache::busy()C
  150. {
  151. if(_to_download.elms() || _to_verify.elms() || _import_images.elms())return true;
  152. REPA(_downloading)if(_downloading[i].state()!=DWNL_NONE)return true;
  153. return false;
  154. }
  155. void InternetCache::enable()
  156. {
  157. App._callbacks.include(ICUpdate, T);
  158. }
  159. void InternetCache::update()
  160. {
  161. // update imported images
  162. REPA(_import_images)
  163. {
  164. ImportImage &ii=_import_images[i];
  165. if(ii.done)
  166. {
  167. Swap(*ii.image_ptr, ii.image_temp);
  168. _import_images.removeValid(i);
  169. }
  170. }
  171. // process downloaded data
  172. REPA(_downloading)
  173. {
  174. Download &down=_downloading[i];
  175. switch(down.state())
  176. {
  177. case DWNL_NONE:
  178. {
  179. if(_to_download.elms()){down.create(_to_download.last() ); _to_download.removeLast();}else
  180. if(_to_verify .elms()){down.create(_to_verify .last(), null, null, -1, -1, 0); _to_verify .removeLast();} // use offset as -1 to encode special mode of verification
  181. }break;
  182. case DWNL_DONE: // finished downloading
  183. {
  184. Str name=ShortName(down.url());
  185. if(down.offset()<0) // if this was verification
  186. {
  187. if(C PakFile *pf=_pak.find(name))if(pf->data_size==down.totalSize() && pf->modify_time_utc==down.modifyTimeUTC()){_verified.binaryInclude(down.url(), COMPARE); down.del(); break;} // file is the same
  188. down.create(Str(down.url())); // it's different so download it fully, copy the 'url' because it might get deleted in the 'create'
  189. }else // move to 'downloaded'
  190. {
  191. Downloaded *downloaded=null; REPA(_downloaded)if(EqualPath(_downloaded[i].name, name)){downloaded=&_downloaded[i]; break;} if(!downloaded)downloaded=&_downloaded.New();
  192. downloaded->name=name;
  193. downloaded->file_data.setNum(down.size()).copyFrom((Byte*)down.data()); downloaded->data.set(downloaded->file_data.data(), downloaded->file_data.elms());
  194. downloaded->modify_time_utc=down.modifyTimeUTC();
  195. downloaded->compress_mode=(Compressable(GetExt(name)) ? COMPRESS_ENABLE : COMPRESS_DISABLE);
  196. ImagePtr img; if(img.find(down.url())) // reload image
  197. {
  198. ImportImage &ii=_import_images.New();
  199. ii.image_ptr=img;
  200. ii.ds =&downloaded->data;
  201. import(ii);
  202. }
  203. _verified.binaryInclude(down.url(), COMPARE);
  204. down.del(); // delete as last
  205. }
  206. }break;
  207. case DWNL_ERROR: down.del(); break; // failed, so just ignore it
  208. }
  209. }
  210. if(busy())enable();
  211. }
  212. /******************************************************************************/
  213. }
  214. /******************************************************************************/