PageRenderTime 30ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/me/itzgeoff/vidsync/server/WatchedFileRouter.java

https://bitbucket.org/itzg/vidsync
Java | 211 lines | 161 code | 44 blank | 6 comment | 16 complexity | a4b715e1b7d97054aa9769e768a2de22 MD5 | raw file
  1. package me.itzgeoff.vidsync.server;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.Collections;
  5. import java.util.LinkedHashSet;
  6. import java.util.Set;
  7. import me.itzgeoff.vidsync.common.MdatSignatureParser;
  8. import me.itzgeoff.vidsync.common.MovieInfo;
  9. import me.itzgeoff.vidsync.common.MovieInfoParser;
  10. import me.itzgeoff.vidsync.common.ResultConsumer;
  11. import me.itzgeoff.vidsync.common.VidSyncException;
  12. import me.itzgeoff.vidsync.domain.common.WatchedFile;
  13. import me.itzgeoff.vidsync.domain.common.WatchedFilesRepository;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.scheduling.annotation.Async;
  18. import org.springframework.stereotype.Component;
  19. @Component
  20. public class WatchedFileRouter {
  21. private class SignatureResultConsumer implements ResultConsumer<File, String> {
  22. @Override
  23. public void consumeResult(File videoFile, String signature) {
  24. logger.debug("Got signature {} for {}", signature, videoFile);
  25. nextFoundSignature(videoFile, signature);
  26. }
  27. @Override
  28. public void failedToReachResult(File videoFile, Exception e) {
  29. logger.error("Unable to parse signature from "+videoFile, e);
  30. out(videoFile);
  31. }
  32. }
  33. private static final Logger logger = LoggerFactory
  34. .getLogger(WatchedFileRouter.class);
  35. @Autowired
  36. private MdatSignatureParser mdatSignatureParser;
  37. @Autowired
  38. private MovieInfoParser movieInfoParser;
  39. @Autowired
  40. private WatchedFilesRepository repository;
  41. @Autowired
  42. private ClientDistributor distributor;
  43. private Set<File> incomingFiles = Collections.synchronizedSet(new LinkedHashSet<File>());
  44. private SignatureResultConsumer signatureResultConsumer = new SignatureResultConsumer();
  45. @Async("worker")
  46. public void in(File videoFile) {
  47. if (!videoFile.exists()) {
  48. logger.debug("Given a file that doesn't actually exist: {}", videoFile);
  49. return;
  50. }
  51. logger.trace("Incoming file {}", videoFile);
  52. if (incomingFiles.add(videoFile)) {
  53. try {
  54. final String canonicalPath = videoFile.getCanonicalPath();
  55. WatchedFile entry = repository.findByPath(canonicalPath);
  56. if (entry == null) {
  57. nextUnknownVideoFile(videoFile);
  58. }
  59. else {
  60. nextPotentiallyKnownVideoFile(entry, videoFile);
  61. }
  62. } catch (IOException e) {
  63. logger.error("Trying to get canonical form {}", e);
  64. }
  65. }
  66. else {
  67. logger.debug("Already tracking incoming {}", videoFile);
  68. }
  69. }
  70. protected void nextPotentiallyKnownVideoFile(WatchedFile entry, File videoFile) throws IOException {
  71. logger.debug("Validating known file {} against {}", entry, videoFile);
  72. if (videoFile.lastModified() == entry.getLastModified() &&
  73. videoFile.length() == entry.getFileSize()) {
  74. logger.debug("Validated {}", videoFile);
  75. entry.setTheFile(videoFile);
  76. distributor.distributeExistingFile(entry, createCompletionConsumer());
  77. return;
  78. }
  79. else {
  80. logger.debug("Modified {} != {} or Size {} != {}", videoFile.lastModified(), entry.getLastModified(),
  81. videoFile.length(), entry.getFileSize());
  82. nextUnknownVideoFile(videoFile);
  83. }
  84. }
  85. protected void nextFoundSignature(final File videoFile, String signature) {
  86. // Look it up by signature to see if only metadata changed
  87. WatchedFile watchedFile = repository.findByContentSignature(signature);
  88. if (watchedFile != null) {
  89. nextPotentiallyChangedFile(videoFile, watchedFile);
  90. }
  91. else {
  92. try {
  93. watchedFile = new WatchedFile(videoFile);
  94. watchedFile.setContentSignature(signature);
  95. MovieInfo movieInfo = movieInfoParser.parse(videoFile);
  96. watchedFile.setTitle(movieInfo.getTitle());
  97. watchedFile = repository.save(watchedFile);
  98. logger.debug("Saved newly watched file {}", watchedFile);
  99. distributor.distributeNewFile(watchedFile, createCompletionConsumer());
  100. } catch (IOException | VidSyncException e) {
  101. out(videoFile);
  102. }
  103. }
  104. }
  105. private ResultConsumer<WatchedFile, Boolean> createCompletionConsumer() {
  106. return new ResultConsumer<WatchedFile, Boolean>() {
  107. @Override
  108. public void failedToReachResult(WatchedFile in, Exception e) {
  109. out(in.getTheFile());
  110. }
  111. @Override
  112. public void consumeResult(WatchedFile in, Boolean result) {
  113. out(in.getTheFile());
  114. }
  115. };
  116. }
  117. public void out(File videoFile) {
  118. logger.trace("Outgoing file {}", videoFile);
  119. incomingFiles.remove(videoFile);
  120. }
  121. protected void nextPotentiallyChangedFile(File videoFile,
  122. WatchedFile watchedFile) {
  123. logger.debug("Checking for potential changes of {}", videoFile);
  124. watchedFile.setTheFile(videoFile);
  125. MovieInfo movieInfo;
  126. try {
  127. movieInfo = movieInfoParser.parse(videoFile);
  128. } catch (IOException | VidSyncException e) {
  129. logger.error("Unable to parse movie info from {}", videoFile);
  130. out(videoFile);
  131. return;
  132. }
  133. if (!movieInfo.getTitle().equals(watchedFile.getTitle())) {
  134. // Update our title info
  135. watchedFile.setTitle(movieInfo.getTitle());
  136. distributor.distributeChangedFile(watchedFile, createCompletionConsumer());
  137. }
  138. else {
  139. // Just a courtesy refresh
  140. distributor.distributeExistingFile(watchedFile, createCompletionConsumer());
  141. }
  142. // Save off any changes to the non-important, but tracked metadata
  143. try {
  144. watchedFile.setPath(videoFile.getCanonicalPath());
  145. } catch (IOException e) {
  146. watchedFile.setPath(videoFile.getAbsolutePath());
  147. }
  148. watchedFile.setFileSize(videoFile.length());
  149. watchedFile.setLastModified(videoFile.lastModified());
  150. watchedFile.setTheFile(videoFile);
  151. // Save it!
  152. WatchedFile saved = repository.save(watchedFile);
  153. logger.debug("Saved updated {}", saved);
  154. }
  155. protected void nextUnknownVideoFile(File videoFile) throws IOException {
  156. logger.debug("Processing unknown file {}", videoFile);
  157. try {
  158. movieInfoParser.validate(videoFile);
  159. logger.debug("Will parse signature of {}", videoFile);
  160. mdatSignatureParser.parseAsync(videoFile, signatureResultConsumer);
  161. } catch (VidSyncException e) {
  162. // Only a debug level since this can happen while the file is still being encoded
  163. logger.debug("Validating file {}", e, videoFile);
  164. out(videoFile);
  165. }
  166. }
  167. }