KMDropboxManager.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. //
  2. // KMDropboxManager.m
  3. // PDF Reader Pro Edition
  4. //
  5. // Created by 万军 on 2020/2/18.
  6. // Copyright © 2020 WanJun. All rights reserved.
  7. //
  8. #import "KMDropboxManager.h"
  9. #import <ObjectiveDropboxOfficial/ObjectiveDropboxOfficial.h>
  10. #import "KMCloudUploadOperationQueue.h"
  11. #import "KMCloudDownloadOperationQueue.h"
  12. #import "DropboxModel.h"
  13. @interface KMDropboxManager ()
  14. @property (nonatomic, copy) NSString *appKey;
  15. //获取本地当前目录下文件列表(仅当前层)
  16. @property (nonatomic, retain) NSMutableArray<KMServicesCloudFile *> *localFileList;
  17. @property (nonatomic, retain) KMServicesCloudFile *localRootFolder;
  18. @property (nonatomic, retain) NSMutableDictionary *cloudFilesCache;
  19. @property (nonatomic, copy) CloudDeleteFileCallBack deleteFileBlock;
  20. @property (nonatomic, copy) CreateFolderCallBack createFolderBlock;
  21. @property (nonatomic, copy) GetFileListCallBack getFileListBlock;
  22. @property (nonatomic, copy) CloudLoginCallBack cloudLoginBlock;
  23. @property (nonatomic, copy) CloudLogoutCallBack cloudLogoutBlock;
  24. @end
  25. @implementation KMDropboxManager
  26. @synthesize appKey = _appKey;
  27. static KMDropboxManager *_instance;
  28. - (void)dealloc {}
  29. + (instancetype)allocWithZone:(struct _NSZone *)zone {
  30. @synchronized(self) {
  31. if (nil == _instance) {
  32. _instance = [super allocWithZone:zone];
  33. }
  34. return _instance;
  35. }
  36. }
  37. + (instancetype)shareInstance {
  38. @synchronized(self) {
  39. if (nil == _instance) {
  40. _instance = [[self alloc] init];
  41. }
  42. return _instance;
  43. }
  44. }
  45. - (id)copyWithZone:(NSZone *)zone
  46. {
  47. return _instance;
  48. }
  49. - (id)mutableCopyWithZone:(NSZone *)zone
  50. {
  51. return _instance;
  52. }
  53. - (id)init {
  54. self = [super init];
  55. if (self) {
  56. _cloudFilesCache = [[NSMutableDictionary alloc] init];
  57. #if VERSION_FREE
  58. self.appKey = @"ksw72buyettl2d4";
  59. #else
  60. #endif
  61. #if VERSION_PRO
  62. self.appKey = @"4tcmyravvap2dmu";
  63. #else
  64. self.appKey = @"4tcmyravvap2dmu";
  65. #endif
  66. NSString *registeredUrlToHandle = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"][0][@"CFBundleURLSchemes"][0];
  67. if (!self.appKey ||
  68. [registeredUrlToHandle rangeOfString:@"<"].location != NSNotFound) {
  69. NSString *message = @"You need to set `appKey` variable in `AppDelegate.m`, as well as add to `Info.plist`, before you can use DBRoulette.";
  70. NSLog(@"%@", message);
  71. exit(1);
  72. }
  73. //初始化DBUserClient实例
  74. // [DBClientsManager setupWithAppKeyDesktop:@"5ep155clehnzu4u"];//jxjlqfm1cfp2mjj
  75. // if (@available(macOS 11.0, *)) { //big sur上必须要
  76. //#if VERSION_PRO
  77. // [DBClientsManager setupWithAppKeyDesktop:@"amipzwtlg9lrwyl"];
  78. //#else
  79. // [DBClientsManager setupWithAppKeyDesktop:@"jxjlqfm1cfp2mjj"];
  80. //#endif
  81. //
  82. // }
  83. [self getList:@""];
  84. [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
  85. andSelector:@selector(handleAppleEvent:withReplyEvent:)
  86. forEventClass:kInternetEventClass
  87. andEventID:kAEGetURL];
  88. }
  89. return self;
  90. }
  91. - (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
  92. // [[DropboxModel shared] handleAppleEvent:event withReplyEvent:replyEvent];
  93. NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
  94. [DBClientsManager handleRedirectURL:url completion:^(DBOAuthResult * _Nullable authResult) {
  95. [[DropboxModel shared] handleAuthResult:authResult];
  96. if (authResult != nil) {
  97. if ([authResult isSuccess]) {
  98. if ([self isSignedIn]) {
  99. DBUserClient *client = [DBClientsManager authorizedClient];
  100. [[client.usersRoutes getCurrentAccount] setResponseBlock:^(DBUSERSFullAccount * _Nullable result, DBNilObject * _Nullable routeError, DBRequestError * _Nullable networkError) {
  101. KMDropboxUserMetadata *model = [[KMDropboxUserMetadata alloc] init];
  102. model.accountId = result.accountId;
  103. model.givenName = result.name.givenName;
  104. model.surname = result.name.surname;
  105. model.email = result.email;
  106. model.emailVerified = result.emailVerified;
  107. model.disabled = result.disabled;
  108. model.country = result.country;
  109. model.locale = result.locale;
  110. model.referralLink = result.locale;
  111. [self setValue:result.accountId forKey:NSStringFromSelector(@selector(accountId))];
  112. [self setValue:[NSString stringWithFormat:@"%@%@",result.name.surname,result.name.givenName] forKey:NSStringFromSelector(@selector(name))];
  113. if (_cloudLoginBlock) {
  114. _cloudLoginBlock(model ,YES);
  115. }
  116. }];
  117. }
  118. [self getList:@""];//获取根目录文件列表
  119. } else if ([authResult isCancel]) {
  120. NSLog(@"Authorization flow was manually canceled by user!");
  121. } else if ([authResult isError]) {
  122. if (_cloudLoginBlock) {
  123. _cloudLoginBlock(nil, NO);
  124. }
  125. }
  126. [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
  127. }
  128. }];
  129. }
  130. - (KMServicesCloudFile *)cloudFolderCacheForDisPath:(NSString *)path
  131. {
  132. if (!path) {
  133. return self.localRootFolder;
  134. } else {
  135. return [self.cloudFilesCache objectForKey:path];
  136. }
  137. }
  138. - (BOOL)isSignedIn
  139. {
  140. return ([DBClientsManager authorizedClient] ? YES : NO);
  141. }
  142. - (NSString *)email {
  143. return [DropboxModel shared].userEmail;
  144. }
  145. #pragma mark - 授权登陆
  146. - (void)authorizedLoginCompletion:(CloudLoginCallBack)completion {
  147. self.cloudLoginBlock = completion;
  148. if (![self isSignedIn]) {
  149. [self dropboxLogin];
  150. } else {
  151. NSLog(@"已登陆");
  152. }
  153. }
  154. - (void)dropboxLogin {
  155. //开始授权流程
  156. NSWindow *window = [NSApplication sharedApplication].mainWindow;
  157. NSViewController *viewC = window.contentViewController;
  158. [DBClientsManager authorizeFromControllerDesktop:[NSWorkspace sharedWorkspace] controller:viewC openURL:^(NSURL * _Nonnull url) {
  159. [[NSWorkspace sharedWorkspace] openURL:url];
  160. }];
  161. }
  162. #pragma mark - 取消授权
  163. - (void)authorizedLogoutCompletion:(CloudLogoutCallBack)completion {
  164. self.cloudLogoutBlock = completion;
  165. if ([DBClientsManager authorizedClient])
  166. {
  167. [DBClientsManager unlinkAndResetClients];
  168. if (_cloudLogoutBlock) {
  169. _cloudLogoutBlock(YES);
  170. }
  171. }
  172. }
  173. #pragma mark - 文件上传
  174. - (KMCloudOperation *)uploadCloudPath:(KMServicesCloudFile *)cloudPath
  175. localPath:(NSURL *)localPath
  176. currentConvetProgress:(CurrentProgressCallBack)currentProgress
  177. completion:(CompletionCallBack)completion
  178. {
  179. KMCloudUploadOperationQueue *queue = [KMCloudUploadOperationQueue sharedInstance];
  180. queue.maxConcurrentOperationCount = 4;
  181. queue.name = [localPath path];
  182. KMCloudOperation *op = [[KMCloudOperation alloc] initWithLoadCloudPath:cloudPath serverType:KMDropbox localPath:localPath loadState:KMCloudLoadState_Upload currentConvetProgress:currentProgress completion:completion];
  183. if (![self isSignedIn]) {
  184. [self dropboxLogin];
  185. } else {
  186. if (![self isLoadOperationExisting:op]) {
  187. [queue addUploadOperation:op];
  188. }
  189. }
  190. return op;
  191. }
  192. - (void)uploadCancel:(KMCloudOperation *)operation {
  193. if ([self isLoadOperationExisting:operation]) {
  194. [operation cancel];
  195. KMCloudUploadOperationQueue *queue = [KMCloudUploadOperationQueue sharedInstance];
  196. [queue cancel:operation.filePath];
  197. [self removeUploadOperation:operation];
  198. } else {
  199. return;
  200. }
  201. }
  202. #pragma mark - 文件下载
  203. - (KMCloudOperation *)downloadCloudPath:(KMServicesCloudFile *)cloudPath
  204. localPath:(NSURL *)localPath
  205. currentConvetProgress:(CurrentProgressCallBack)currentProgress
  206. completion:(CompletionCallBack)completion
  207. {
  208. KMCloudDownloadOperationQueue *queue = [KMCloudDownloadOperationQueue sharedInstance];
  209. queue.maxConcurrentOperationCount = 4;
  210. queue.name = cloudPath.displayName;
  211. KMCloudOperation *op = [[KMCloudOperation alloc] initWithLoadCloudPath:cloudPath
  212. serverType:KMDropbox
  213. localPath:localPath
  214. loadState:KMCloudLoadState_Download
  215. currentConvetProgress:currentProgress
  216. completion:completion];
  217. if (![self isSignedIn]) {
  218. [self dropboxLogin];
  219. } else {
  220. if (![self isLoadOperationExisting:op]) {
  221. [queue addDownloadOperation:op];
  222. }
  223. }
  224. return op;
  225. }
  226. - (void)downloadCancel:(KMCloudOperation *)operation {
  227. if ([self isLoadOperationExisting:operation]) {
  228. [operation cancel];
  229. KMCloudDownloadOperationQueue *queue = [KMCloudDownloadOperationQueue sharedInstance];
  230. [queue cancel:operation.filePath];
  231. [self removeDownloadOperation:operation];
  232. } else {
  233. return;
  234. }
  235. }
  236. #pragma mark - 文件删除
  237. - (void)deleteFileWithPath:(KMServicesCloudFile *)fileData
  238. completion:(CloudDeleteFileCallBack)completion
  239. {
  240. self.deleteFileBlock = completion;
  241. if (![self isSignedIn]) {
  242. [self dropboxLogin];
  243. } else {
  244. DBUserClient *client = [DBClientsManager authorizedClient];
  245. // [[client.filesRoutes delete_:fileData.path_display] setResponseBlock:^(DBFILESDeleteResult * _Nullable result, DBFILESDeleteError * _Nullable routeError, DBRequestError * _Nullable networkError) {
  246. // if (result) {
  247. // NSString *folderPath = [self getFolderPathWithFileData:fileData];
  248. // KMDropboxFileMetadata *fileModel = [[KMDropboxFileMetadata alloc] init];
  249. // fileModel.name = result.metadata.name;
  250. // fileModel.path_lower = result.metadata.pathLower;
  251. // fileModel.path_display = result.metadata.pathDisplay;
  252. // if (_deleteFileBlock) {
  253. // _deleteFileBlock(fileData, YES);
  254. // }
  255. // [self getList:folderPath];
  256. // } else {
  257. // KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
  258. // errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
  259. // errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
  260. // if (_deleteFileBlock) {
  261. // _deleteFileBlock(fileData, NO);
  262. // }
  263. // }
  264. // }];
  265. //
  266. // [[client.filesRoutes delete_V2:fileData.path_display] setResponseBlock:^(DBFILESDeleteResult * _Nullable result, DBFILESDeleteError * _Nullable routeError, DBRequestError * _Nullable networkError) {
  267. // if (result) {
  268. // NSString *folderPath = [self getFolderPathWithFileData:fileData];
  269. // KMDropboxFileMetadata *fileModel = [[KMDropboxFileMetadata alloc] init];
  270. // fileModel.name = result.metadata.name;
  271. // fileModel.path_lower = result.metadata.pathLower;
  272. // fileModel.path_display = result.metadata.pathDisplay;
  273. // if (_deleteFileBlock) {
  274. // _deleteFileBlock(fileData, YES);
  275. // }
  276. // [self getList:folderPath];
  277. // } else {
  278. // KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
  279. // errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
  280. // errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
  281. // if (_deleteFileBlock) {
  282. // _deleteFileBlock(fileData, NO);
  283. // }
  284. // }
  285. // }];
  286. }
  287. }
  288. #pragma mark - 文件夹创建
  289. - (void)createFolderWithPath:(KMServicesCloudFile *)fileData
  290. folderName:(NSString *)folderName
  291. completion:(CreateFolderCallBack)completion
  292. {
  293. self.createFolderBlock = completion;
  294. NSString *pathUrl = [self getFolderPathWithFileData:fileData];
  295. if (![self isSignedIn]) {
  296. [self dropboxLogin];
  297. } else {
  298. DBUserClient *client = [DBClientsManager authorizedClient];
  299. // [[client.filesRoutes createFolderV2:[NSString stringWithFormat:@"%@/%@",pathUrl,folderName]] setResponseBlock:^(DBFILESCreateFolderResult * _Nullable result, DBFILESCreateFolderError * _Nullable routeError, DBRequestError * _Nullable networkError) {
  300. // if (result) {
  301. //
  302. // KMDropboxFileMetadata *fileModel = [[KMDropboxFileMetadata alloc] init];
  303. // fileModel.id_ = result.metadata.id_;
  304. // fileModel.name = result.metadata.name;
  305. // fileModel.path_lower = result.metadata.pathLower;
  306. // fileModel.path_display = result.metadata.pathDisplay;
  307. // if (_createFolderBlock) {
  308. // _createFolderBlock(fileModel, YES);
  309. // }
  310. // [self getList:pathUrl];
  311. // } else {
  312. // KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
  313. // errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
  314. // errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
  315. // if (_createFolderBlock) {
  316. // _createFolderBlock(fileData, YES);
  317. // }
  318. // }
  319. // }];
  320. }
  321. }
  322. #pragma mark - 文件列表信息
  323. - (void) getListWithFilePath:(KMServicesCloudFile *)fileData
  324. setResponseBlock:(GetFileListCallBack)responseBlock
  325. {
  326. self.getFileListBlock = responseBlock;
  327. NSString *pathUrl = [self getFolderPathWithFileData:fileData];
  328. if (fileData.displayName) {
  329. [self.cloudFilesCache setValue:fileData forKey:fileData.displayName];
  330. }
  331. if (![self isSignedIn]) {
  332. [self dropboxLogin];
  333. } else if ([pathUrl isEqualToString:@""] || pathUrl == nil) {
  334. [self getList:pathUrl];
  335. } else {
  336. _localFileList = [[NSMutableArray alloc] init];
  337. DBUserClient *client = [DBClientsManager authorizedClient];
  338. [[client.filesRoutes listFolder:pathUrl]
  339. setResponseBlock:^(DBFILESListFolderResult *response, DBFILESListFolderError *routeError, DBRequestError *networkError) {
  340. if (response) {
  341. NSArray<DBFILESMetadata *> *entries = response.entries;
  342. [self printEntries:entries];
  343. if (![response.hasMore boolValue]) {
  344. if (_getFileListBlock) {
  345. _getFileListBlock(_localFileList,KMDropbox,nil);
  346. [_localFileList removeAllObjects];
  347. }
  348. }
  349. } else {
  350. KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
  351. errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
  352. errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
  353. if (_getFileListBlock) {
  354. _getFileListBlock(nil,KMDropbox,nil);
  355. }
  356. }
  357. }];
  358. }
  359. }
  360. - (void)getList:(NSString *)filePath {
  361. _localFileList = [[NSMutableArray alloc] init];
  362. DBUserClient *client = [DBClientsManager authorizedClient];
  363. [[client.filesRoutes listFolder:filePath.length < 1 ? @"" :filePath]
  364. setResponseBlock:^(DBFILESListFolderResult *response, DBFILESListFolderError *routeError, DBRequestError *networkError) {
  365. if (response) {
  366. NSArray<DBFILESMetadata *> *entries = response.entries;
  367. BOOL hasMore = [response.hasMore boolValue];
  368. [self printEntries:entries];
  369. if (hasMore) {
  370. //is folder
  371. // [self listFolderContinueWithClient:client cursor:cursor];
  372. } else {
  373. NSLog(@"List folder complete.");
  374. }
  375. if (_getFileListBlock) {
  376. _getFileListBlock(_localFileList,KMDropbox,nil);
  377. [_localFileList removeAllObjects];
  378. }
  379. } else {
  380. KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
  381. errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
  382. errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
  383. if (_getFileListBlock) {
  384. _getFileListBlock(nil,KMDropbox,nil);
  385. }
  386. }
  387. }];
  388. }
  389. - (void)printEntries:(NSArray<DBFILESMetadata *> *)entries {
  390. for (DBFILESMetadata *entry in entries) {
  391. KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
  392. if ([entry isKindOfClass:[DBFILESFileMetadata class]]) {
  393. DBFILESFileMetadata *fileMetadata = (DBFILESFileMetadata *)entry;
  394. fileModel.client_modified = fileMetadata.clientModified;
  395. fileModel.content_hash = fileMetadata.contentHash;
  396. fileModel.fileId = fileMetadata.id_;
  397. fileModel.displayName = fileMetadata.pathDisplay;
  398. fileModel.path_lower = fileMetadata.pathLower;
  399. fileModel.rev = fileMetadata.rev;
  400. fileModel.fileModiDate = fileMetadata.serverModified;
  401. fileModel.fileSize = fileMetadata.size.integerValue;
  402. fileModel.filetype = KMCloudServiceFileType_File;
  403. fileModel.fileName = fileMetadata.name;
  404. [_localFileList addObject:fileModel];
  405. } else if ([entry isKindOfClass:[DBFILESFolderMetadata class]]) {
  406. DBFILESFolderMetadata *folderMetadata = (DBFILESFolderMetadata *)entry;
  407. fileModel.fileId = folderMetadata.id_;
  408. fileModel.fileName = folderMetadata.name;
  409. fileModel.displayName = folderMetadata.pathDisplay;
  410. fileModel.path_lower = folderMetadata.pathLower;
  411. fileModel.filetype = KMCloudServiceFileType_Folder;
  412. [_localFileList addObject:fileModel];
  413. }
  414. }
  415. }
  416. #pragma mark - private methods
  417. - (void)removeUploadOperation:(KMCloudOperation *)operation {
  418. KMCloudUploadOperationQueue *queue = [KMCloudUploadOperationQueue sharedInstance];
  419. if ([queue isUploadOperationExisting:operation.filePath]) {
  420. NSLog(@"removeUploadOperation operation.filePath == %@",operation.filePath);
  421. [queue cancel:operation.filePath];
  422. }
  423. }
  424. - (void)removeDownloadOperation:(KMCloudOperation *)operation {
  425. KMCloudDownloadOperationQueue *queue = [KMCloudDownloadOperationQueue sharedInstance];
  426. if ([queue isDownloadOperationExisting:operation.filePath]) {
  427. NSLog(@"removeOperation operation.filePath == %@",operation.filePath);
  428. [queue cancel:operation.filePath];
  429. }
  430. }
  431. - (BOOL)isLoadOperationExisting:(KMCloudOperation *)operation {
  432. KMCloudUploadOperationQueue *uploadQueue = [KMCloudUploadOperationQueue sharedInstance];
  433. KMCloudDownloadOperationQueue *downloadQueue = [KMCloudDownloadOperationQueue sharedInstance];
  434. NSMutableArray *operationArr = [NSMutableArray array];
  435. for (NSArray *opArr in @[uploadQueue.operations, downloadQueue.operations]) {
  436. for (int j = 0; j < opArr.count; j++) {
  437. [operationArr addObject:opArr[j]];
  438. }
  439. }
  440. for (KMCloudOperation *op in operationArr) {
  441. if ([op.filePath isEqualToString:operation.filePath]) {
  442. return YES;
  443. }
  444. }
  445. return NO;
  446. }
  447. //获取文件对象所处的文件夹路径
  448. - (NSString *)getFolderPathWithFileData:(KMServicesCloudFile *)fileData {
  449. if (KMCloudServiceFileType_Folder == fileData.filetype) {
  450. return fileData.displayName;
  451. } else {
  452. NSString *folderPath = [fileData.displayName stringByDeletingLastPathComponent];
  453. if ([folderPath isEqualToString:@"/"]) {
  454. return @"";
  455. } else {
  456. return folderPath;
  457. }
  458. }
  459. return nil;
  460. }
  461. - (KMServicesCloudFile *)localRootFolder {
  462. KMServicesCloudFile *fileData = [[KMServicesCloudFile alloc] init];
  463. fileData.displayName = @"";
  464. fileData.path_lower = @"";
  465. fileData.filetype = KMCloudServiceFileType_Folder;
  466. return fileData;
  467. }
  468. @end