XSDataCenter.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. //
  2. // XSDataCenter.m
  3. // XenonSDK
  4. //
  5. // Created by SAGESSE on 2019/5/30.
  6. // Copyright © 2019 SAGESSE. All rights reserved.
  7. //
  8. #import "XenonSDK.h"
  9. #import "XSDataCenter.h"
  10. #if SDK_USE_DATA_DB
  11. #import <sqlite3.h>
  12. #endif
  13. @implementation XSDataCenter
  14. + (NSString*)path {
  15. return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) firstObject];
  16. }
  17. #if SDK_USE_DATA_DB
  18. + (sqlite3*)db {
  19. static sqlite3* db = nil;
  20. static dispatch_once_t onceToken;
  21. dispatch_once(&onceToken, ^{
  22. // Check file path.
  23. if (![NSFileManager.defaultManager fileExistsAtPath:self.path]) {
  24. [NSFileManager.defaultManager createDirectoryAtPath:self.path withIntermediateDirectories:YES attributes:nil error:nil];
  25. }
  26. NSString* path = [self.path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.db", NSStringFromClass(self)]];
  27. if (sqlite3_open(path.UTF8String, &db) != 0) {
  28. db = nil;
  29. return;
  30. }
  31. if (sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS 'DC' ('key' TEXT NOT NULL PRIMARY KEY, 'value' TEXT, 'isa' TEXT);", nil, nil, nil) != 0) {
  32. db = nil;
  33. return;
  34. }
  35. });
  36. return db;
  37. }
  38. #endif
  39. + (void)setString:(id)value forKey:(id)key {
  40. [self setValue:[NSArray arrayWithObject:value]
  41. forKey:key];
  42. }
  43. + (id)stringForKey:(id)key {
  44. return [[self valueForKey:key] firstObject];
  45. }
  46. + (void)setDouble:(CGFloat)value forKey:(id)key {
  47. [self setValue:@[@(value)]
  48. forKey:key];
  49. }
  50. + (CGFloat)doubleForKey:(id)key {
  51. return [[[self valueForKey:key] firstObject] doubleValue];
  52. }
  53. + (void)setValue:(id)value forKey:(id)key {
  54. // Must be locked.
  55. @synchronized (self) {
  56. // To data;
  57. id isa = NSStringFromClass([value class]);
  58. id json = value;
  59. if ([json isKindOfClass:NSArray.class]) {
  60. __block id nisa = nil;
  61. NSMutableArray* res = [NSMutableArray array];
  62. [json enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  63. if ([obj isKindOfClass:JSONModel.class]) {
  64. nisa = NSStringFromClass([obj class]);
  65. [res addObject:[obj toDictionary]];
  66. } else {
  67. nisa = nil;
  68. *stop = YES;
  69. }
  70. }];
  71. // Same type.
  72. if (nisa != nil) {
  73. json = res;
  74. isa = nisa;
  75. }
  76. }
  77. if ([json isKindOfClass:JSONModel.class]) {
  78. json = [value toDictionary];
  79. }
  80. if (json != nil) {
  81. id data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
  82. json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; ;
  83. }
  84. #if SDK_USE_DATA_DB
  85. NSString* dw = sdk_md5(key);
  86. NSString* dsql = [NSString stringWithFormat:@"DELETE FROM DC WHERE key = '%@';", dw];
  87. sqlite3_exec(self.db, dsql.UTF8String, nil, nil, nil);
  88. if (json != nil) {
  89. NSString* base64 = [[json dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
  90. NSString* isql = [NSString stringWithFormat:@"INSERT INTO DC (key, value, isa) VALUES ('%@', '%@', '%@');", dw, base64, isa];
  91. sqlite3_exec(self.db, isql.UTF8String, nil, nil, nil);
  92. }
  93. #endif
  94. #if SDK_USE_DATA_UD
  95. if (value == nil) {
  96. [NSUserDefaults.standardUserDefaults setObject:nil forKey:key];
  97. [NSUserDefaults.standardUserDefaults synchronize];
  98. } else {
  99. [NSUserDefaults.standardUserDefaults setObject:@[isa, json] forKey:key];
  100. [NSUserDefaults.standardUserDefaults synchronize];
  101. }
  102. #endif
  103. #if SDK_USE_DATA_FILE
  104. // Check file path.
  105. if (![NSFileManager.defaultManager fileExistsAtPath:self.path]) {
  106. [NSFileManager.defaultManager createDirectoryAtPath:self.path withIntermediateDirectories:YES attributes:nil error:nil];
  107. }
  108. // Make new path.
  109. NSString* path = [self.path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.db", sdk_md5(key)]];
  110. if (value == nil) {
  111. [NSFileManager.defaultManager removeItemAtPath:path error:nil];
  112. } else {
  113. [@[isa, json] writeToFile:path atomically:YES];
  114. }
  115. #endif
  116. }
  117. }
  118. + (id)valueForKey:(id)key {
  119. // Must be locked.
  120. @synchronized (self) {
  121. NSString* isa = nil;
  122. NSString* json = nil;
  123. #if SDK_USE_DATA_DB
  124. NSString* dw = sdk_md5(key);
  125. NSString* qsql = [NSString stringWithFormat:@"SELECT isa, value FROM DC WHERE key = '%@';", dw];
  126. sqlite3_stmt* stmt = nil;
  127. if (sqlite3_prepare_v2(self.db, qsql.UTF8String, -1, &stmt, nil) != 0) {
  128. return nil;
  129. }
  130. sqlite3_step(stmt);
  131. void* col1 = (void*)sqlite3_column_text(stmt, 0);
  132. void* col2 = (void*)sqlite3_column_text(stmt, 1);
  133. if (col1 != nil) {
  134. isa = [NSString stringWithUTF8String:col1];
  135. }
  136. if (col2 != nil) {
  137. NSData* data = [[NSData alloc] initWithBase64EncodedString:[NSString stringWithUTF8String:col2] options:0];
  138. json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  139. }
  140. sqlite3_finalize(stmt);
  141. #endif
  142. #if SDK_USE_DATA_UD
  143. NSArray* uaw = [NSUserDefaults.standardUserDefaults arrayForKey:key];
  144. if (uaw.count == 2) {
  145. isa = uaw[0];
  146. json = uaw[1];
  147. }
  148. #endif
  149. #if SDK_USE_DATA_FILE
  150. // Make new path.
  151. NSString* path = [self.path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.db", sdk_md5(key)]];
  152. NSArray* faw = [NSArray arrayWithContentsOfFile:path];
  153. if (faw.count == 2) {
  154. isa = faw[0];
  155. json = faw[1];
  156. }
  157. #endif
  158. if (isa != nil || json != nil) {
  159. Class cls = NSClassFromString(isa);
  160. NSData* data = [json dataUsingEncoding:NSUTF8StringEncoding];
  161. id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  162. if ([cls isSubclassOfClass:JSONModel.class]) {
  163. if ([object isKindOfClass:NSArray.class]) {
  164. return [cls arrayOfModelsFromDictionaries:object error:nil];
  165. }
  166. return [[cls alloc] initWithDictionary:object error:nil];
  167. }
  168. return object;
  169. }
  170. return nil;
  171. }
  172. }
  173. //class func set<T: Encodable>(_ value: T?, forKey key: String) {
  174. //
  175. //}
  176. //
  177. //class func value<T: Decodable>(forKey key: String) -> T? {
  178. // // Must be locked.
  179. // objc_sync_enter(self)
  180. // defer {
  181. // objc_sync_exit(self)
  182. // }
  183. //
  184. // var value: T?
  185. //
  186. //#if SDK_USE_DATA_DB
  187. // var stmt: UnsafeRawPointer?
  188. // guard sqlite3_prepare_v2(db, "SELECT value FROM DC WHERE key = '\(sdk_md5(key))';", -1, &stmt, nil) == 0 else {
  189. // return nil
  190. // }
  191. // defer {
  192. // _ = sqlite3_finalize(stmt)
  193. // }
  194. // _ = sqlite3_step(stmt)
  195. // guard let ptr = sqlite3_column_text(stmt, 0), let str = NSString(cString: ptr, encoding: String.Encoding.utf8.rawValue) else {
  196. // return nil
  197. // }
  198. // let data = Data(base64Encoded: str as String)
  199. // let decoder = PropertyListDecoder()
  200. // value = try? data.map { try decoder.decode(T.self, from: $0) }
  201. //#endif
  202. //
  203. //#if SDK_USE_DATA_UD
  204. // let data = UserDefaults.standard.data(forKey: defaultName)
  205. // let decoder = PropertyListDecoder()
  206. // value = try? data.map { try decoder.decode(T.self, from: $0) }
  207. //#endif
  208. //
  209. //#if SDK_USE_DATA_FILE
  210. // guard let path = XSDataCenter.path else {
  211. // return nil
  212. // }
  213. // var url = URL(fileURLWithPath: path)
  214. // url.appendPathComponent("\(sdk_md5(key)).db")
  215. // let data = try? Data(contentsOf: url)
  216. // let decoder = PropertyListDecoder()
  217. // value = try? data.map { try decoder.decode(T.self, from: $0) }
  218. //#endif
  219. //
  220. // return value
  221. //}
  222. @end