KTVHCDataFileSource.m 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //
  2. // KTVHCDataFileSource.m
  3. // KTVHTTPCache
  4. //
  5. // Created by Single on 2017/8/11.
  6. // Copyright © 2017年 Single. All rights reserved.
  7. //
  8. #import "KTVHCDataFileSource.h"
  9. #import "KTVHCDataCallback.h"
  10. #import "KTVHCError.h"
  11. #import "KTVHCLog.h"
  12. @interface KTVHCDataFileSource () <NSLocking>
  13. @property (nonatomic, strong) NSLock *coreLock;
  14. @property (nonatomic, strong) NSFileHandle *readingHandle;
  15. @end
  16. @implementation KTVHCDataFileSource
  17. @synthesize error = _error;
  18. @synthesize range = _range;
  19. @synthesize closed = _closed;
  20. @synthesize prepared = _prepared;
  21. @synthesize finished = _finished;
  22. @synthesize readedLength = _readedLength;
  23. - (instancetype)initWithPath:(NSString *)path range:(KTVHCRange)range readRange:(KTVHCRange)readRange
  24. {
  25. if (self = [super init])
  26. {
  27. KTVHCLogAlloc(self);
  28. self->_path = path;
  29. self->_range = range;
  30. self->_readRange = readRange;
  31. self.coreLock = [[NSLock alloc] init];
  32. KTVHCLogDataFileSource(@"%p, Create file source\npath : %@\nrange : %@\nreadRange : %@", self, path, KTVHCStringFromRange(range), KTVHCStringFromRange(readRange));
  33. }
  34. return self;
  35. }
  36. - (void)dealloc
  37. {
  38. KTVHCLogDealloc(self);
  39. }
  40. - (void)prepare
  41. {
  42. [self lock];
  43. if (self.isPrepared) {
  44. [self unlock];
  45. return;
  46. }
  47. KTVHCLogDataFileSource(@"%p, Call prepare", self);
  48. self.readingHandle = [NSFileHandle fileHandleForReadingAtPath:self.path];
  49. @try {
  50. [self.readingHandle seekToFileOffset:self.readRange.start];
  51. self->_prepared = YES;
  52. if ([self.delegate respondsToSelector:@selector(ktv_fileSourceDidPrepare:)]) {
  53. KTVHCLogDataFileSource(@"%p, Callback for prepared - Begin", self);
  54. [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
  55. KTVHCLogDataFileSource(@"%p, Callback for prepared - End", self);
  56. [self.delegate ktv_fileSourceDidPrepare:self];
  57. }];
  58. }
  59. } @catch (NSException *exception) {
  60. KTVHCLogDataFileSource(@"%p, Seek file exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
  61. NSError *error = [KTVHCError errorForException:exception];
  62. [self callbackForFailed:error];
  63. }
  64. [self unlock];
  65. }
  66. - (void)close
  67. {
  68. [self lock];
  69. if (self.isClosed) {
  70. [self unlock];
  71. return;
  72. }
  73. self->_closed = YES;
  74. KTVHCLogDataFileSource(@"%p, Call close", self);
  75. [self destoryReadingHandle];
  76. [self unlock];
  77. }
  78. - (NSData *)readDataOfLength:(NSUInteger)length
  79. {
  80. [self lock];
  81. if (self.isClosed) {
  82. [self unlock];
  83. return nil;
  84. }
  85. if (self.isFinished) {
  86. [self unlock];
  87. return nil;
  88. }
  89. NSData *data = nil;
  90. @try {
  91. long long readLength = KTVHCRangeGetLength(self.readRange);
  92. length = (NSUInteger)MIN(readLength - self.readedLength, length);
  93. data = [self.readingHandle readDataOfLength:length];
  94. self->_readedLength += data.length;
  95. if (data.length > 0) {
  96. KTVHCLogDataFileSource(@"%p, Read data : %lld, %lld, %lld", self, (long long)data.length, self.readedLength, readLength);
  97. }
  98. if (self.readedLength >= readLength) {
  99. KTVHCLogDataFileSource(@"%p, Read data did finished", self);
  100. [self destoryReadingHandle];
  101. self->_finished = YES;
  102. }
  103. } @catch (NSException *exception) {
  104. KTVHCLogDataFileSource(@"%p, Read exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
  105. NSError *error = [KTVHCError errorForException:exception];
  106. [self callbackForFailed:error];
  107. }
  108. [self unlock];
  109. return data;
  110. }
  111. - (void)destoryReadingHandle
  112. {
  113. if (self.readingHandle) {
  114. @try {
  115. [self.readingHandle closeFile];
  116. } @catch (NSException *exception) {
  117. KTVHCLogDataFileSource(@"%p, Close exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
  118. }
  119. self.readingHandle = nil;
  120. }
  121. }
  122. - (void)callbackForFailed:(NSError *)error
  123. {
  124. if (!error) {
  125. return;
  126. }
  127. if (self.error) {
  128. return;
  129. }
  130. self->_error = error;
  131. if ([self.delegate respondsToSelector:@selector(ktv_fileSource:didFailWithError:)]) {
  132. KTVHCLogDataFileSource(@"%p, Callback for prepared - Begin", self);
  133. [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
  134. KTVHCLogDataFileSource(@"%p, Callback for prepared - End", self);
  135. [self.delegate ktv_fileSource:self didFailWithError:self.error];
  136. }];
  137. }
  138. }
  139. - (void)setDelegate:(id <KTVHCDataFileSourceDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue
  140. {
  141. self->_delegate = delegate;
  142. self->_delegateQueue = delegateQueue;
  143. }
  144. - (void)lock
  145. {
  146. [self.coreLock lock];
  147. }
  148. - (void)unlock
  149. {
  150. [self.coreLock unlock];
  151. }
  152. @end