-
Notifications
You must be signed in to change notification settings - Fork 2
feat: added changes for seq id changes #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vkalta
wants to merge
8
commits into
next
Choose a base branch
from
feat/seq_id
base: next
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d199774
Merge pull request #8 from contentstack/next
uttamukkoji f82db75
feat: added changes for seq id changes
81c71ca
fix: minor fix
dd0ac2d
fix: added separated methods for sync with seq id
8610950
fix: minor changes
a47c622
fix: minor changes
eb2cdd0
feat: added git action for release
3181f14
fix: updated license
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| name: Contentstack iOS Persistence SDK Release | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| jobs: | ||
| release: | ||
| name: Release Contentstack iOS Persistence SDK Release | ||
| runs-on: macos-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v2 | ||
|
|
||
| - name: Select Xcode | ||
| run: sudo xcode-select -switch /Applications/Xcode.app && /usr/bin/xcodebuild -version | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pod install --repo-update | ||
|
|
||
| - name: Build | ||
| run: | | ||
| # Add commands to build and test your package | ||
| xcodebuild -workspace ContentstackPersistence.xcworkspace -scheme 'ContentstackPersistence' -destination 'platform=iOS Simulator,name=iPhone 13 Pro' | ||
|
|
||
| - name: Tag release | ||
| id: tag | ||
| run: | | ||
| git tag v0.1.2 # Replace with your desired version number | ||
| echo "::set-output name=tag::v0.1.2" # Replace with the same version number as above | ||
|
|
||
| - name: Push tag | ||
| uses: ad-m/github-push-action@v0.6.0 | ||
| with: | ||
| github_token: ${{ secrets.GITHUB_TOKEN }} | ||
| tag: ${{ steps.tag.outputs.tag }} | ||
|
|
||
| - name: CocoaPods trunk push | ||
| run: pod trunk push | ||
| env: | ||
| COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // | ||
| // BSONOIDGenerator.h | ||
| // ContentstackPersistence | ||
| // | ||
| // Created by Vikram Kalta on 13/02/2024. | ||
| // Copyright © 2024 Contentstack. All rights reserved. | ||
| // | ||
|
|
||
| #ifndef BSONOIDGenerator_h | ||
| #define BSONOIDGenerator_h | ||
|
|
||
| #import <Foundation/Foundation.h> | ||
|
|
||
| typedef union { | ||
| char bytes[12]; | ||
| int ints[3]; | ||
| } bson_oid_t; | ||
|
|
||
| @interface BSONOIDGenerator : NSObject | ||
|
|
||
| + (NSString *)generate:(NSInteger)timestamp; | ||
|
|
||
| @end | ||
|
|
||
| #endif /* BSONOIDGenerator_h */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| // | ||
| // BSONOIDGenerator.m | ||
| // ContentstackPersistence | ||
| // | ||
| // Created by Vikram Kalta on 13/02/2024. | ||
| // Copyright © 2024 Contentstack. All rights reserved. | ||
| // | ||
|
|
||
| #import <Foundation/Foundation.h> | ||
| #import <CommonCrypto/CommonDigest.h> | ||
| #import "BSONOIDGenerator.h" | ||
| #import <UIKit/UIKit.h> | ||
|
|
||
| @implementation BSONOIDGenerator | ||
| static int _incr = 0; | ||
|
|
||
| + (NSString *) generate:(NSInteger)timestamp { | ||
| int i = _incr++; | ||
| bson_oid_t *oid = malloc(sizeof(bson_oid_t)); | ||
| time_t t = time(NULL); | ||
|
|
||
| // Grab the PID | ||
| int pid = [NSProcessInfo processInfo].processIdentifier; | ||
|
|
||
| // Get a device identifier. The specification usually has this as the MAC address | ||
| // or hostname but we already have a unique device identifier. | ||
| // | ||
| NSString *identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; | ||
|
|
||
| // MD5 hash the device identifier | ||
| NSString *md5HashOfIdentifier = [self md5HashFromString:identifier]; | ||
| const char *cIdentifier = [md5HashOfIdentifier cStringUsingEncoding:NSUTF8StringEncoding]; | ||
|
|
||
| // Copy bytes over to our object id. Specification taken from http://www.mongodb.org/display/DOCS/Object+IDs | ||
| bson_swap_endian_len(&oid->bytes[0], ×tamp, 4); | ||
| bson_swap_endian_len(&oid->bytes[4], &cIdentifier, 3); | ||
| bson_swap_endian_len(&oid->bytes[7], &pid, 2); | ||
| bson_swap_endian_len(&oid->bytes[9], &i, 3); | ||
| NSString *str = [self bson_oid_to_string:oid]; | ||
|
|
||
| free(oid); | ||
|
|
||
| return str; | ||
| } | ||
|
|
||
| /** | ||
| @discussion Given an NSString, returns the MD5 hash of it. Taken from | ||
| http://stackoverflow.com/questions/1524604/md5-algorithm-in-objective-c | ||
| @param source The source string | ||
| @return MD5 hash as a string | ||
| */ | ||
| + (NSString *) md5HashFromString:(NSString *)source { | ||
| const char *cStr = [source UTF8String]; | ||
| unsigned char result[16]; | ||
| CC_MD5(cStr, strlen(cStr), result); | ||
| return [NSString stringWithFormat: | ||
| @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", | ||
| result[0], result[1], result[2], result[3], | ||
| result[4], result[5], result[6], result[7], | ||
| result[8], result[9], result[10], result[11], | ||
| result[12], result[13], result[14], result[15] | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| @discussion Converts a bson_oid_t to an NSString. Mostly taken from https://github.com/mongodb/mongo-c-driver/blob/master/src/bson.c | ||
| @param oid The bson_oid_t to convert | ||
| @return Autoreleased NSString of 24 hex characters | ||
| */ | ||
| + (NSString *) bson_oid_to_string:(bson_oid_t *)oid { | ||
| char *str = malloc(sizeof(char) * 25); | ||
| static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; | ||
| int i; | ||
| for ( i=0; i<12; i++ ) { | ||
| str[2*i] = hex[( oid->bytes[i] & 0xf0 ) >> 4]; | ||
| str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ]; | ||
| } | ||
| str[24] = '\0'; | ||
| NSString *string = [NSString stringWithCString:str encoding:NSUTF8StringEncoding]; | ||
| free(str); | ||
| return string; | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| @discussion The ARM architecture is little endian while intel macs are big Endian, so we need to swap endianness if we're compiling on a big Endian architecture. | ||
| @param outp The destination pointer | ||
| @param inp The source pointer | ||
| @param len The length to copy | ||
| */ | ||
| void bson_swap_endian_len(void *outp, const void *inp, int len) { | ||
| const char *in = (const char *)inp; | ||
| char *out = (char *)outp; | ||
| for (int i = 0; i < len; i ++) { | ||
| #if __DARWIN_BIG_ENDIAN | ||
| out[i] = in[len - 1 - i]; | ||
| #elif __DARWIN_LITTLE_ENDIAN | ||
| out[i] = in[i]; | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| @end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,8 @@ | |
| #import "PersistenceModel.h" | ||
| #import <CoreData/CoreData.h> | ||
| #import <objc/runtime.h> | ||
| #import "CSIOInternalHeaders.h" | ||
| #import "BSONOIDGenerator.h" | ||
|
|
||
| @implementation SyncManageSwiftSupport | ||
| + (BOOL)isSwiftClassName:(NSString *)className { | ||
|
|
@@ -92,24 +94,35 @@ -(NSString*) getSyncToken { | |
| return syncToken; | ||
| } | ||
|
|
||
| -(NSString*) getSeqId { | ||
| __block NSString *seqId; | ||
| [self.persistanceDelegate performBlockAndWait:^{ | ||
| id<SyncStoreProtocol> syncStack = [self findOrCreate:self->_syncStack predicate:nil]; | ||
| seqId = syncStack.seqId; | ||
| }]; | ||
| return seqId; | ||
| } | ||
|
|
||
| -(void)updateSyncStack:(SyncStack*)syncStack { | ||
| id<SyncStoreProtocol> syncStore = (id<SyncStoreProtocol>)[self findOrCreate:_syncStack predicate:nil]; | ||
| syncStore.syncToken = syncStack.syncToken; | ||
| syncStore.paginationToken = syncStack.paginationToken; | ||
| syncStore.seqId = syncStack.seqId; | ||
| } | ||
|
|
||
| -(void)syncWithInit:(BOOL) shouldInit onCompletion:(void (^)(double, BOOL, NSError * _Nullable))completion { | ||
| NSString *paginationToken = [self getPaginationToken];//csb0e8704474a9624785098d233edd2715` | ||
| NSString *syncToken = [self getSyncToken];//cse053899d15e9e94cd3751df26f719c87 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commented tokens should be removed
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @ishaileshmishra , yes they are removed. |
||
| /* The following method will be deprecated soon */ | ||
| -(void)syncWithInit:(BOOL) shouldInit syncToken:(NSString *)syncToken onCompletion:(void (^)(double, BOOL, NSError * _Nullable))completion { | ||
| __weak typeof (self) weakSelf = self; | ||
| NSString *paginationToken = [self getPaginationToken]; | ||
|
|
||
| id completionBlock = ^(SyncStack * _Nullable syncStack, NSError * _Nullable error) { | ||
| if (error != nil) { | ||
| //Init the sync API on pagination and sync token errors | ||
| if (error.code == 422) { | ||
| if (error.userInfo && error.userInfo[@"errors"]) { | ||
| NSDictionary *errors = error.userInfo[@"errors"]; | ||
| if (errors[@"pagination_token"] || errors[@"sync_token"]) { | ||
| [weakSelf syncWithInit:true onCompletion:completion]; | ||
| [weakSelf syncWithInit:true syncToken:nil onCompletion:completion]; | ||
| return; | ||
| } | ||
| } | ||
|
|
@@ -153,7 +166,6 @@ -(void)syncWithInit:(BOOL) shouldInit onCompletion:(void (^)(double, BOOL, NSErr | |
| }]; | ||
| completion(self.percentageComplete, isSyncCompleted, error); | ||
| } | ||
|
|
||
| }; | ||
| if (shouldInit) { | ||
| self.percentageComplete = 0; | ||
|
|
@@ -168,8 +180,117 @@ -(void)syncWithInit:(BOOL) shouldInit onCompletion:(void (^)(double, BOOL, NSErr | |
| } | ||
| } | ||
|
|
||
| -(void)syncWithSeqId:(NSString *)seqId syncToken:(NSString *)syncToken onCompletion:(void (^)(double, BOOL, NSError * _Nullable))completion { | ||
| __weak typeof (self) weakSelf = self; | ||
| id completionBlock = ^(SyncStack * _Nullable syncStack, NSError * _Nullable error) { | ||
| if (error != nil) { | ||
| //Init the sync API on pagination and sync token errors | ||
| if (error.code == 422) { | ||
| if (error.userInfo && error.userInfo[@"errors"]) { | ||
| NSDictionary *errors = error.userInfo[@"errors"]; | ||
| if (errors[@"seq_id"]) { | ||
| [weakSelf syncWithSeqId:nil syncToken:nil onCompletion:completion]; | ||
| return; | ||
| } | ||
| } | ||
| } | ||
| completion(self.percentageComplete, false, error); | ||
| } else { | ||
| __block BOOL isSyncCompleted = false; | ||
| [self.persistanceDelegate performBlockAndWait:^{ | ||
|
|
||
| if (syncStack.items) { | ||
| self.percentageComplete = ((double)(syncStack.skip) + (double)syncStack.items.count) / (double)syncStack.totalCount; | ||
|
|
||
| if (syncToken && syncStack.seqId == nil && syncStack.items.count > 0) { | ||
| // Generate seq id. | ||
| [self generateAndPersistSeqId:syncStack]; | ||
| } | ||
| } | ||
|
|
||
| //entry_unpublished || entry_deleted | ||
| NSArray *deletedEntryArray = [syncStack.items filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type = 'entry_unpublished' || type = 'entry_deleted' "]]; | ||
| [self deleteEntries:deletedEntryArray]; | ||
|
|
||
| //asset_unpublished || asset_deleted | ||
| if (self->_asset != nil) { | ||
| NSArray *deletedAssetsArray = [syncStack.items filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type = 'asset_unpublished' || type = 'asset_deleted'"]]; | ||
| [self.persistanceDelegate delete:self->_asset inUid:[deletedAssetsArray valueForKeyPath:@"data.uid"]]; | ||
| } | ||
|
|
||
| //asset_published | ||
| NSArray *publishAssetArray = [syncStack.items filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type = 'asset_published'"]]; | ||
| [self createAssets:publishAssetArray]; | ||
|
|
||
| //entry_published | ||
| NSArray *publishEntryArray = [syncStack.items filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type = 'entry_published'"]]; | ||
| [self createEntries:publishEntryArray]; | ||
|
|
||
| //Sync toke Update | ||
| if (syncStack.seqId != nil) { | ||
| isSyncCompleted = true; | ||
| [self updateSyncStack:syncStack]; | ||
| } | ||
| //Save context | ||
| if ([self.persistanceDelegate respondsToSelector:@selector(save)]) { | ||
| [self.persistanceDelegate save]; | ||
| } | ||
| }]; | ||
| completion(self.percentageComplete, isSyncCompleted, error); | ||
| } | ||
| }; | ||
| if (seqId != nil) { | ||
| [_stack syncSeqId:seqId syncToken:syncToken completion:completionBlock]; | ||
| } else if (syncToken != nil) { | ||
| [_stack syncSeqId:seqId syncToken:syncToken completion:completionBlock]; | ||
| } else { | ||
| self.percentageComplete = 0; | ||
| [_stack initSeqSync:completionBlock]; | ||
| } | ||
| } | ||
|
|
||
| -(void)generateAndPersistSeqId:(SyncStack * _Nullable)syncStack { | ||
| // Get the last object's event_at | ||
| NSDictionary *lastObject = nil; | ||
| for (NSInteger i = syncStack.items.count - 1; i >= 0; i--) { | ||
| id object = syncStack.items[i]; | ||
| if ([object isKindOfClass:[NSDictionary class]]) { | ||
| lastObject = object; | ||
| break; | ||
| } | ||
| } | ||
| syncStack.seqId = [self generateSeqId:[lastObject objectForKey:@"event_at"]]; | ||
| syncStack.syncToken = nil; | ||
|
|
||
| } | ||
|
|
||
| -(NSString *)generateSeqId:(NSString *)eventAt { | ||
| // Create a date formatter to parse the date string | ||
| NSDateFormatter *dateFormater = [[NSDateFormatter alloc] init]; | ||
| dateFormater.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; | ||
| NSDate *date = [dateFormater dateFromString:eventAt]; | ||
| if (date) { | ||
| // Convert the NSDate object to an NSTimeInterval | ||
| NSTimeInterval timeInterval = [date timeIntervalSince1970]; | ||
| NSInteger timeIntervalInSeconds = (NSInteger)timeInterval; | ||
| return [BSONOIDGenerator generate:timeIntervalInSeconds]; | ||
| } else { | ||
| // Handle case where date conversion failed. | ||
| [NSException raise:@"Unable to parse date string" format:@"Invalid date format %@", eventAt]; | ||
| return nil; | ||
| } | ||
| } | ||
|
|
||
| -(void)sync:(void (^)(double, BOOL, NSError * _Nullable))completion { | ||
| [self syncWithInit:false onCompletion:completion]; | ||
| NSString *syncToken = [self getSyncToken]; | ||
| NSString *seqId = [self getSeqId]; | ||
| if (syncToken) { | ||
| [self syncWithSeqId:nil syncToken:syncToken onCompletion:completion]; | ||
| } else if (seqId) { | ||
| [self syncWithSeqId:seqId syncToken:nil onCompletion:completion]; | ||
| } else { | ||
| [self syncWithSeqId:nil syncToken:nil onCompletion:completion]; | ||
| } | ||
| } | ||
|
|
||
| -(void)createAssets:(NSArray*)assetsArray { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented tokens should be removed