diff --git a/android/app/build.gradle b/android/app/build.gradle index c472ebc7..ee36a081 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -174,6 +174,8 @@ dependencies { compile "com.mixpanel.android:mixpanel-android:4.+" compile "com.jakewharton.timber:timber:4.3.1" compile "com.facebook.fresco:animated-gif:0.11.0" + compile "com.amazonaws:aws-android-sdk-core:2.2.+" + compile "com.amazonaws:aws-android-sdk-kinesis:2.2.+" } // Run this once to be able to run the application with BUCK diff --git a/android/app/src/main/java/co/backbonelabs/backbone/BackbonePackage.java b/android/app/src/main/java/co/backbonelabs/backbone/BackbonePackage.java index 1d6b1ba0..3f7a9ae7 100644 --- a/android/app/src/main/java/co/backbonelabs/backbone/BackbonePackage.java +++ b/android/app/src/main/java/co/backbonelabs/backbone/BackbonePackage.java @@ -25,6 +25,7 @@ public List createViewManagers(ReactApplicationContext reactContext public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); modules.add(new EnvironmentModule(reactContext)); + modules.add(UserService.getInstance(reactContext)); modules.add(new Mixpanel(reactContext)); modules.add(BluetoothService.getInstance(reactContext)); modules.add(BootLoaderService.getInstance(reactContext)); diff --git a/android/app/src/main/java/co/backbonelabs/backbone/SessionControlService.java b/android/app/src/main/java/co/backbonelabs/backbone/SessionControlService.java index ab288034..fd9bfe86 100644 --- a/android/app/src/main/java/co/backbonelabs/backbone/SessionControlService.java +++ b/android/app/src/main/java/co/backbonelabs/backbone/SessionControlService.java @@ -7,9 +7,16 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; +import com.amazonaws.AmazonClientException; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.CognitoCachingCredentialsProvider; +import com.amazonaws.mobileconnectors.kinesis.kinesisrecorder.KinesisFirehoseRecorder; +import com.amazonaws.regions.Regions; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; @@ -18,6 +25,10 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + import co.backbonelabs.backbone.util.Constants; import co.backbonelabs.backbone.util.EventEmitter; import co.backbonelabs.backbone.util.JSError; @@ -27,6 +38,35 @@ public class SessionControlService extends ReactContextBaseJavaModule { private static SessionControlService instance = null; private ReactApplicationContext reactContext; + private final String TAG = "SessionControlService"; + + private KinesisFirehoseRecorder firehoseRecorder; + private SimpleDateFormat timestampFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS"); + private boolean shouldFlushFirehoseRecords = true; + + private int currentSessionState = Constants.SESSION_STATES.STOPPED; + private int previousSessionState = Constants.SESSION_STATES.STOPPED; + private int currentCommand; + + private int sessionDuration = Constants.SESSION_DEFAULT_DURATION; + private int slouchDistanceThreshold = Constants.SLOUCH_DEFAULT_DISTANCE_THRESHOLD; + private int slouchTimeThreshold = Constants.SLOUCH_DEFAULT_TIME_THRESHOLD; + + private int vibrationPattern = Constants.VIBRATION_DEFAULT_PATTERN; + private int vibrationSpeed = Constants.VIBRATION_DEFAULT_SPEED; + private int vibrationDuration = Constants.VIBRATION_DEFAULT_DURATION; + + private boolean distanceNotificationStatus; + private boolean statisticNotificationStatus; + private boolean slouchNotificationStatus; + + private boolean forceStoppedSession; + private boolean notificationStateChanged; + + private long sessionStartTimestamp; + private String sessionId = ""; + + private Constants.IntCallBack errorCallBack; public static SessionControlService getInstance() { return instance; @@ -43,6 +83,30 @@ private SessionControlService(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; + timestampFormatter.setTimeZone(TimeZone.getTimeZone("GMT")); + + // Set up Firehose + Regions region = Regions.US_WEST_2; + AWSCredentialsProvider provider = new CognitoCachingCredentialsProvider( + reactContext, + Constants.AMAZON_COGNITO_IDENTITY_POOL, + region + ); + + firehoseRecorder = new KinesisFirehoseRecorder( + reactContext.getCacheDir(), + region, + provider + ); + + // Submit any pending Firehose records + submitFirehoseRecords(); + + // Load details of previous session, if any + SharedPreferences preferences = reactContext.getSharedPreferences(Constants.POSTURE_SESSION_PREFERENCES, Context.MODE_PRIVATE); + sessionId = preferences.getString(Constants.POSTURE_SESSION_PREFERENCE_SESSION_ID, null); + sessionStartTimestamp = preferences.getLong(Constants.POSTURE_SESSION_PREFERENCE_START_TIMESTAMP, 0); + IntentFilter filter = new IntentFilter(); filter.addAction(Constants.ACTION_CHARACTERISTIC_READ); filter.addAction(Constants.ACTION_CHARACTERISTIC_UPDATE); @@ -108,27 +172,6 @@ public void onActivityDestroyed(Activity activity) { }); } - private int currentSessionState = Constants.SESSION_STATES.STOPPED; - private int previousSessionState = Constants.SESSION_STATES.STOPPED; - private int currentCommand; - - private int sessionDuration = Constants.SESSION_DEFAULT_DURATION; - private int slouchDistanceThreshold = Constants.SLOUCH_DEFAULT_DISTANCE_THRESHOLD; - private int slouchTimeThreshold = Constants.SLOUCH_DEFAULT_TIME_THRESHOLD; - - private int vibrationPattern = Constants.VIBRATION_DEFAULT_PATTERN; - private int vibrationSpeed = Constants.VIBRATION_DEFAULT_SPEED; - private int vibrationDuration = Constants.VIBRATION_DEFAULT_DURATION; - - private boolean distanceNotificationStatus; - private boolean statisticNotificationStatus; - private boolean slouchNotificationStatus; - - private boolean forceStoppedSession; - private boolean notificationStateChanged; - - private Constants.IntCallBack errorCallBack; - @Override public String getName() { return "SessionControlService"; @@ -319,6 +362,7 @@ public void getSessionState() { } private void toggleSessionOperation(int operation, Constants.IntCallBack errCallBack) { + Timber.d("Toggle Session Control %d", operation); BluetoothService bluetoothService = BluetoothService.getInstance(); previousSessionState = currentSessionState; @@ -328,6 +372,25 @@ private void toggleSessionOperation(int operation, Constants.IntCallBack errCall boolean status; if (operation == Constants.SESSION_OPERATIONS.START) { + // We generate the session id locally on the phone because we can't rely on the user + // being connected to the internet when starting a session. This session id will be + // sent to our data warehouse. The session id format is the user id and current + // timestamp in seconds separated by a hyphen. + String userId = UserService.getInstance().getUserId(); + if (userId == null) { + userId = ""; + } + sessionStartTimestamp = System.currentTimeMillis(); + sessionId = userId + "-" + (sessionStartTimestamp / 1000); + Timber.d("sessionId %s", sessionId); + + // Store session details in case app is terminated in the middle of a posture session + SharedPreferences preference = reactContext.getSharedPreferences(Constants.POSTURE_SESSION_PREFERENCES, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preference.edit(); + editor.putString(Constants.POSTURE_SESSION_PREFERENCE_SESSION_ID, sessionId); + editor.putLong(Constants.POSTURE_SESSION_PREFERENCE_START_TIMESTAMP, sessionStartTimestamp); + editor.commit(); + int sessionDurationInSecond = sessionDuration * 60; // Convert to second from minute byte[] commandBytes = new byte[12]; @@ -354,6 +417,10 @@ private void toggleSessionOperation(int operation, Constants.IntCallBack errCall slouchNotificationStatus = true; statisticNotificationStatus = true; + // Toggle accelerometer notification separately because the app doesn't rely on the + // accelerometer notifications to monitor a posture session + bluetoothService.toggleCharacteristicNotification(Constants.CHARACTERISTIC_UUIDS.ACCELEROMETER_CHARACTERISTIC, true); + status = bluetoothService.writeToCharacteristic(Constants.CHARACTERISTIC_UUIDS.SESSION_CONTROL_CHARACTERISTIC, commandBytes); } else if (operation == Constants.SESSION_OPERATIONS.RESUME) { @@ -376,6 +443,10 @@ else if (operation == Constants.SESSION_OPERATIONS.RESUME) { slouchNotificationStatus = true; statisticNotificationStatus = true; + // Toggle accelerometer notification separately because the app doesn't rely on the + // accelerometer notifications to monitor a posture session + bluetoothService.toggleCharacteristicNotification(Constants.CHARACTERISTIC_UUIDS.ACCELEROMETER_CHARACTERISTIC, true); + status = bluetoothService.writeToCharacteristic(Constants.CHARACTERISTIC_UUIDS.SESSION_CONTROL_CHARACTERISTIC, commandBytes); } else { @@ -397,18 +468,26 @@ else if (operation == Constants.SESSION_OPERATIONS.RESUME) { slouchNotificationStatus = false; statisticNotificationStatus = false; + // Save session record for Firehose + saveSessionToFirehose(); + + // Submit all pending Firehose records + submitFirehoseRecords(); + break; } + // Toggle accelerometer notification separately because the app doesn't rely on the + // accelerometer notifications to monitor a posture session + bluetoothService.toggleCharacteristicNotification(Constants.CHARACTERISTIC_UUIDS.ACCELEROMETER_CHARACTERISTIC, false); + status = bluetoothService.writeToCharacteristic(Constants.CHARACTERISTIC_UUIDS.SESSION_CONTROL_CHARACTERISTIC, commandBytes); } - Timber.d("Toggle Session Control %d", operation); - - // There won't be any response back from the board once it failed here - // So if we failed initiating the characteristic writer, handle the error callback right away if (!status) { - Log.e("SessionControlService", "Error initiating session control update"); + // There won't be any response back from the board if + // writing to the session control characteristic failed + Log.e(TAG, "Error initiating session control update"); errorCallBack.onIntCallBack(1); errorCallBack = null; } @@ -440,6 +519,49 @@ else if (currentCommand == Constants.SESSION_OPERATIONS.PAUSE) { } } + /** + * Saves a posture session record to Firehose and clears the session details from SharedPreferences + */ + private void saveSessionToFirehose() { + Timber.d("saveSessionToFirehose"); + String userId = UserService.getInstance().getUserId(); + if (userId == null) { + userId = ""; + } + + String startDateTime = timestampFormatter.format(new Date(sessionStartTimestamp)); + String endDateTime = timestampFormatter.format(new Date()); + String record = String.format("%s,%s,%s,%s\n", sessionId, userId, startDateTime, endDateTime); + Timber.d("Firehose posture session record: %s", record); + firehoseRecorder.saveRecord(record, Constants.FIREHOSE_STREAMS.POSTURE_SESSION); + + // Remove session data + SharedPreferences preferences = reactContext.getSharedPreferences(Constants.POSTURE_SESSION_PREFERENCES, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.commit(); + } + + /** + * Submit all pending Firehose records + */ + private void submitFirehoseRecords() { + new AsyncTask() { + @Override + protected Void doInBackground(Void... v) { + try { + Timber.d("Submitting Firehose records"); + firehoseRecorder.submitAllRecords(); + } catch (AmazonClientException ace) { + Log.e(TAG, "Error submitting to Firehose"); + Log.e(TAG, Log.getStackTraceString(ace)); + } + shouldFlushFirehoseRecords = true; + return null; + } + }.execute(); + } + private final BroadcastReceiver bleBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -522,6 +644,8 @@ else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.SESSION_STATISTIC_CHARACTERI MainActivity.currentActivity.startService(stopIntent); if (!forceStoppedSession) { + // Session automatically stopped + Timber.d("Session automatically stopped"); errorCallBack = null; currentSessionState = Constants.SESSION_STATES.STOPPED; @@ -530,7 +654,52 @@ else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.SESSION_STATISTIC_CHARACTERI statisticNotificationStatus = false; slouchNotificationStatus = false; + bluetoothService.toggleCharacteristicNotification(Constants.CHARACTERISTIC_UUIDS.ACCELEROMETER_CHARACTERISTIC, false); bluetoothService.toggleCharacteristicNotification(Constants.CHARACTERISTIC_UUIDS.SESSION_DATA_CHARACTERISTIC, distanceNotificationStatus); + + // Save session record for Firehose + saveSessionToFirehose(); + + // Submit pending Firehose records + submitFirehoseRecords(); + } + } + else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.ACCELEROMETER_CHARACTERISTIC.toString())) { + byte[] responseArray = intent.getByteArrayExtra(Constants.EXTRA_BYTE_VALUE); + + if (currentSessionState == Constants.SESSION_STATES.RUNNING) { + // Only save data to Firehose if session is running in case other modules are + // enabling accelerometer notifications outside of a posture session + float x = Utilities.getFloatFromByteArray(responseArray, 0); + float y = Utilities.getFloatFromByteArray(responseArray, 4); + float z = Utilities.getFloatFromByteArray(responseArray, 8); + + Timber.d("Accelerometer data %f %f %f", x, y, z); + + // Queue accelerometer record for Firehose + String now = timestampFormatter.format(new Date()); + firehoseRecorder.saveRecord(String.format("%s,%s,%f,%f,%f\n", sessionId, now, x, y, z), Constants.FIREHOSE_STREAMS.POSTURE_SESSION_STREAM); + + // Periodically submit records to Firehose to make + // sure the storage limit isn't reached. This will be + // done when the storage usage is at 50%, 75%, and 90%. + long storageLimit = firehoseRecorder.getDiskByteLimit(); + long storageUsed = firehoseRecorder.getDiskBytesUsed(); + float storageUsage = (float)storageUsed / storageLimit; + if (storageUsage >= 0.9 && shouldFlushFirehoseRecords) { + shouldFlushFirehoseRecords = false; + submitFirehoseRecords(); + } else if (storageUsage >= 0.76) { + shouldFlushFirehoseRecords = true; + } else if (storageUsage >= 0.75 && shouldFlushFirehoseRecords) { + shouldFlushFirehoseRecords = false; + submitFirehoseRecords(); + } else if (storageUsage >= 0.51) { + shouldFlushFirehoseRecords = true; + } else if (storageUsage >= 0.5 && shouldFlushFirehoseRecords) { + shouldFlushFirehoseRecords = false; + submitFirehoseRecords(); + } } } } @@ -548,14 +717,14 @@ else if (action.equals(Constants.ACTION_CHARACTERISTIC_WRITE)) { // If we failed initiating the descriptor writer, handle the error callback if (!toggleStatus && errorCallBack != null) { - Log.e("SessionControlService", "Error toggling notification"); + Log.e(TAG, "Error toggling session data notification"); errorCallBack.onIntCallBack(1); errorCallBack = null; } } } else { - Log.e("SessionControlService", "Error writing into session control"); + Log.e(TAG, "Error writing into session control characteristic"); if (errorCallBack != null) { errorCallBack.onIntCallBack(1); errorCallBack = null; @@ -576,7 +745,7 @@ else if (action.equals(Constants.ACTION_DESCRIPTOR_WRITE)) { // If we failed initiating the descriptor writer, handle the error callback if (!toggleStatus) { - Log.e("SessionControlService", "Error toggling notification"); + Log.e(TAG, "Error toggling slouch notification"); errorCallBack.onIntCallBack(1); errorCallBack = null; @@ -585,7 +754,7 @@ else if (action.equals(Constants.ACTION_DESCRIPTOR_WRITE)) { } } else { - Log.e("SessionControlService", "Error writing into notification descriptor"); + Log.e(TAG, "Error writing into session data notification descriptor"); if (errorCallBack != null) { // Properly handle the failure when we failed toggling the notification state errorCallBack.onIntCallBack(1); @@ -602,7 +771,7 @@ else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.SLOUCH_CHARACTERISTIC.toStri // If we failed initiating the descriptor writer, handle the error callback if (!toggleStatus) { - Log.e("SessionControlService", "Error toggling notification"); + Log.e(TAG, "Error toggling session statistic notification"); errorCallBack.onIntCallBack(1); errorCallBack = null; @@ -612,7 +781,7 @@ else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.SLOUCH_CHARACTERISTIC.toStri } } else { - Log.e("SessionControlService", "Error writing into notification descriptor"); + Log.e(TAG, "Error writing into slouch notification descriptor"); if (errorCallBack != null) { // Properly handle the failure when we failed toggling the notification state errorCallBack.onIntCallBack(1); @@ -631,7 +800,7 @@ else if (uuid.equals(Constants.CHARACTERISTIC_UUIDS.SESSION_STATISTIC_CHARACTERI } } else { - Log.e("SessionControlService", "Error writing into notification descriptor"); + Log.e(TAG, "Error writing into session statistic notification descriptor"); if (errorCallBack != null) { // Properly handle the failure when we failed toggling the notification state errorCallBack.onIntCallBack(1); diff --git a/android/app/src/main/java/co/backbonelabs/backbone/UserService.java b/android/app/src/main/java/co/backbonelabs/backbone/UserService.java new file mode 100644 index 00000000..b7fc8565 --- /dev/null +++ b/android/app/src/main/java/co/backbonelabs/backbone/UserService.java @@ -0,0 +1,47 @@ +package co.backbonelabs.backbone; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +public class UserService extends ReactContextBaseJavaModule { + private static UserService instance = null; + private ReactApplicationContext reactContext; + + private String id; + + public static UserService getInstance() { + return instance; + } + + public static UserService getInstance(ReactApplicationContext reactContext) { + if (instance == null) { + instance = new UserService(reactContext); + } + return instance; + } + + private UserService(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "UserService"; + } + + public String getUserId() { + return id; + } + + @ReactMethod + public void setUserId(String userId) { + id = userId; + } + + @ReactMethod + public void unsetUserId() { + id = null; + } +} diff --git a/android/app/src/main/java/co/backbonelabs/backbone/util/Constants.java b/android/app/src/main/java/co/backbonelabs/backbone/util/Constants.java index badf612a..84f86f6f 100644 --- a/android/app/src/main/java/co/backbonelabs/backbone/util/Constants.java +++ b/android/app/src/main/java/co/backbonelabs/backbone/util/Constants.java @@ -270,4 +270,14 @@ public interface MapCallBack { public static final String NOTIFICATION_PARAMETER_SCHEDULED_MINUTE = "scheduledMinute"; public static final String NOTIFICATION_PARAMETER_SCHEDULED_SECOND = "scheduledSecond"; public static final String NOTIFICATION_PARAMETER_SCHEDULED_TIMESTAMP = "scheduledTimestamp"; + + public static final String POSTURE_SESSION_PREFERENCES = "co.backbonelabs.backbone.POSTURE_SESSION_PREFERENCES"; + public static final String POSTURE_SESSION_PREFERENCE_SESSION_ID = "sessionId"; + public static final String POSTURE_SESSION_PREFERENCE_START_TIMESTAMP = "startTimestamp"; + + public static final String AMAZON_COGNITO_IDENTITY_POOL = "us-west-2:70f7284b-3235-4b4d-82d5-bab9df3d80f5"; + public interface FIREHOSE_STREAMS { + String POSTURE_SESSION_STREAM = "PostureSessionAccelerometerDeliveryStream"; + String POSTURE_SESSION = "PostureSessionDeliveryStream"; + } } diff --git a/app/actions/auth.js b/app/actions/auth.js index 16222fdc..b337bcd2 100644 --- a/app/actions/auth.js +++ b/app/actions/auth.js @@ -12,7 +12,7 @@ import constants from '../utils/constants'; import Bugsnag from '../utils/Bugsnag'; import Mixpanel from '../utils/Mixpanel'; -const { Environment } = NativeModules; +const { Environment, UserService } = NativeModules; const { storageKeys, errorMessages } = constants; const handleNetworkError = mixpanelEvent => { @@ -42,12 +42,16 @@ export default { throw new Error(body.error); } else { const { accessToken, ...userObj } = body; + const id = userObj._id; + + // Store user id on the native side + UserService.setUserId(id); // Identify user for Bugsnag - Bugsnag.setUser(userObj._id, userObj.nickname, userObj.email); + Bugsnag.setUser(id, userObj.nickname, userObj.email); // Identify user for Mixpanel tracking - Mixpanel.identify(userObj._id); + Mixpanel.identify(id); // Update user profile on Mixpanel Mixpanel.setUserProperties(userObj); @@ -83,11 +87,16 @@ export default { throw new Error(body.error); } else { + const id = body.user._id; + + // Store user id on the native side + UserService.setUserId(id); + // Identify user for Bugsnag - Bugsnag.setUser(body.user._id, body.user.nickname, body.user.email); + Bugsnag.setUser(id, body.user.nickname, body.user.email); // Identify user for Mixpanel tracking - Mixpanel.identify(body.user._id); + Mixpanel.identify(id); // Update user profile in Mixpanel Mixpanel.setUserProperties(body.user); @@ -135,6 +144,7 @@ export default { }, signOut() { + UserService.unsetUserId(); Bugsnag.clearUser(); Mixpanel.track('signOut'); diff --git a/app/containers/Application.js b/app/containers/Application.js index addc9add..9b82f17e 100644 --- a/app/containers/Application.js +++ b/app/containers/Application.js @@ -47,6 +47,7 @@ const { Environment, SessionControlService, DeviceInformationService, + UserService, } = NativeModules; const BluetoothServiceEvents = new NativeEventEmitter(BluetoothService); @@ -368,11 +369,16 @@ class Application extends Component { payload: user, }); + const id = user._id; + + // Store user id on the native side + UserService.setUserId(id); + // Identify user for Bugsnag - Bugsnag.setUser(user._id, user.nickname, user.email); + Bugsnag.setUser(id, user.nickname, user.email); // Identify user for Mixpanel - Mixpanel.identify(user._id); + Mixpanel.identify(id); if (user.hasOnboarded) { // User completed onboarding diff --git a/ios/Backbone.xcodeproj/project.pbxproj b/ios/Backbone.xcodeproj/project.pbxproj index cfe62145..cc107b6e 100644 --- a/ios/Backbone.xcodeproj/project.pbxproj +++ b/ios/Backbone.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 6625BB8B1DB1E5E9009B4941 /* MixpanelModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 6625BB8A1DB1E5E9009B4941 /* MixpanelModule.m */; }; 662BD3491DFC92E900CF71D1 /* Debug.local.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 662BD3481DFC92E900CF71D1 /* Debug.local.xcconfig */; }; 662BD36F1DFC933F00CF71D1 /* Release.local.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 662BD36E1DFC933F00CF71D1 /* Release.local.xcconfig */; }; + 66351EB31EE098B200383F23 /* UserService.m in Sources */ = {isa = PBXBuildFile; fileRef = 66351EB21EE098B200383F23 /* UserService.m */; }; 665924E81DD430FA00F5C2C1 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 665924E71DD430FA00F5C2C1 /* MaterialIcons.ttf */; }; 667641271D63B90800D45761 /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = 667641261D63B90800D45761 /* Environment.m */; }; 66F9187B1DA9F82B00649391 /* Lato.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 66F918791DA9F82B00649391 /* Lato.ttf */; }; @@ -332,6 +333,8 @@ 6625BB8A1DB1E5E9009B4941 /* MixpanelModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MixpanelModule.m; path = backbone/MixpanelModule.m; sourceTree = ""; }; 662BD3481DFC92E900CF71D1 /* Debug.local.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.local.xcconfig; path = backbone/config/Debug.local.xcconfig; sourceTree = ""; }; 662BD36E1DFC933F00CF71D1 /* Release.local.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Release.local.xcconfig; path = backbone/config/Release.local.xcconfig; sourceTree = ""; }; + 66351E8E1EE093AE00383F23 /* UserService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserService.h; path = backbone/UserService.h; sourceTree = ""; }; + 66351EB21EE098B200383F23 /* UserService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UserService.m; path = backbone/UserService.m; sourceTree = ""; }; 665924E71DD430FA00F5C2C1 /* MaterialIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; }; 667641251D63B8F900D45761 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Environment.h; path = backbone/Environment.h; sourceTree = ""; }; 667641261D63B90800D45761 /* Environment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Environment.m; path = backbone/Environment.m; sourceTree = ""; }; @@ -521,6 +524,8 @@ 699262611DE58A28003FBBC7 /* SessionControlService.m */, 690301FC1EA7A68C00A59FD4 /* VibrationMotorService.h */, 690301FD1EA7A68D00A59FD4 /* VibrationMotorService.m */, + 66351E8E1EE093AE00383F23 /* UserService.h */, + 66351EB21EE098B200383F23 /* UserService.m */, ); name = Backbone; sourceTree = ""; @@ -1265,7 +1270,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; C759A8355A6451A7CFEF9959 /* [CP] Check Pods Manifest.lock */ = { @@ -1280,7 +1285,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -1300,6 +1305,7 @@ files = ( 699262621DE58A28003FBBC7 /* SessionControlService.m in Sources */, 667641271D63B90800D45761 /* Environment.m in Sources */, + 66351EB31EE098B200383F23 /* UserService.m in Sources */, 69EB80551E0170E200A29ADA /* BootLoaderService.m in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 690301FE1EA7A68D00A59FD4 /* VibrationMotorService.m in Sources */, diff --git a/ios/Podfile b/ios/Podfile index 18bdd126..ead4c7c5 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -8,6 +8,8 @@ target 'Backbone' do # Pods for Backbone pod 'Mixpanel' + pod 'AWSCognito' + pod 'AWSKinesis' target 'BackboneTests' do inherit! :search_paths diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2888bbeb..f1e7543c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,14 +1,24 @@ PODS: + - AWSCognito (2.5.6): + - AWSCore (= 2.5.6) + - AWSCore (2.5.6) + - AWSKinesis (2.5.6): + - AWSCore (= 2.5.6) - Mixpanel (3.0.8): - Mixpanel/Mixpanel (= 3.0.8) - Mixpanel/Mixpanel (3.0.8) DEPENDENCIES: + - AWSCognito + - AWSKinesis - Mixpanel SPEC CHECKSUMS: + AWSCognito: 18edcf80780d45229371dc954c77c825c617f9c4 + AWSCore: 47109d026cdbc1272624caa73114fbdd2ba3ad66 + AWSKinesis: fcd6511b82be0b48c423838de52519e158ba46eb Mixpanel: 550a23d5dd95f8e9cda21e697661ffddbc8da46b -PODFILE CHECKSUM: 4c137f7b98316ab4d541a1b3fb02f3cbcfd9be85 +PODFILE CHECKSUM: bdbd7a22b2cc0156b6967f496ab6ded18243ad73 -COCOAPODS: 1.1.1 +COCOAPODS: 1.2.1 diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognito.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognito.h new file mode 100644 index 00000000..de0a4b9b --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognito.h @@ -0,0 +1,31 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +//! Project version number for AWSCognito. +FOUNDATION_EXPORT double AWSCognitoVersionNumber; + +//! Project version string for AWSCognito. +FOUNDATION_EXPORT const unsigned char AWSCognitoVersionString[]; + +#import "AWSCognitoService.h" +#import "AWSCognitoDataset.h" +#import "AWSCognitoRecord.h" +#import "AWSCognitoHandlers.h" +#import "AWSCognitoConflict.h" +#import "AWSCognitoSyncService.h" diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.h new file mode 100644 index 00000000..d9ef7d8e --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.h @@ -0,0 +1,72 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class AWSCognitoRecord; + +/** + An object that encapsulates a resolved conflict in Amazon Cognito. + */ +@interface AWSCognitoResolvedConflict : NSObject +@end + +/** + An object that encapsulates a tuple of Amazon Cognito records. + */ +@interface AWSCognitoRecordTuple : NSObject +/** + The local copy of the record. + */ +@property (nonatomic, readonly) AWSCognitoRecord *localRecord; +/** + The remote (cloud) copy of the record. + */ +@property (nonatomic, readonly) AWSCognitoRecord *remoteRecord; +@end + +/** + An object that encapsulates a conflicting record where both + the local and remote have been modified since the last synchronization. + */ +@interface AWSCognitoConflict : AWSCognitoRecordTuple + +/** + Create a AWSCognitoResolvedConflict object with the value of the + local record. + + @return AWSCognitoResolvedConflict object using local value + */ +-(AWSCognitoResolvedConflict *) resolveWithLocalRecord; +/** + Create a AWSCognitoResolvedConflict object with the value of the + remote (cloud) record. + + @return AWSCognitoResolvedConflict object using remote (cloud) value + */ +-(AWSCognitoResolvedConflict *) resolveWithRemoteRecord; +/** + Create a AWSCognitoResolvedConflict object with a custom value that + is neither the local nor remote value. + + @param value the value to use to resolve the conflict + + @return AWSCognitoResolvedConflict object using passed value + */ +-(AWSCognitoResolvedConflict *) resolveWithValue:(NSString *)value; +@end + diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.m b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.m new file mode 100644 index 00000000..1d0e5c9f --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoConflict.m @@ -0,0 +1,89 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoConflict_Internal.h" +#import "AWSCognitoRecord.h" + + +@implementation AWSCognitoRecordTuple +-(instancetype) initWithLocalRecord:(AWSCognitoRecord *) local remoteRecord:(AWSCognitoRecord *) remote { + self = [super init]; + if (nil != self) { + _localRecord = local; + _remoteRecord = remote; + } + return self; +} +@end + +@implementation AWSCognitoConflict +-(AWSCognitoResolvedConflict *) resolveWithLocalRecord { + return [AWSCognitoResolvedConflict resolvedConflictWithLocalRecord:self]; +} + +-(AWSCognitoResolvedConflict *) resolveWithRemoteRecord { + return [AWSCognitoResolvedConflict resolvedConflictWithRemoteRecord:self]; +} + +-(AWSCognitoResolvedConflict *) resolveWithValue:(NSString *)value { + return [AWSCognitoResolvedConflict resolvedConflictWithValue:self newValue:value]; +} + +@end + +@implementation AWSCognitoResolvedConflict +- (instancetype) initWithRemoteRecord:(AWSCognitoConflict *) conflict { + self = [super init]; + if (nil != self) { + _conflict = conflict; + _resolvedConflict = [conflict.remoteRecord copy]; + } + return self; +} + +- (instancetype) initWithLocalRecord:(AWSCognitoConflict *) conflict { + self = [super init]; + if (nil != self) { + _conflict = conflict; + _resolvedConflict = [conflict.localRecord copy]; + _resolvedConflict.syncCount = conflict.remoteRecord.syncCount; + } + return self; +} + +- (instancetype) initWithValue:(AWSCognitoConflict *)conflict newValue:(NSString *)value { + self = [self initWithLocalRecord:conflict]; + if (nil != self) { + _resolvedConflict.data = [[AWSCognitoRecordValue alloc] initWithString:value]; + } + return self; +} + ++ (instancetype) resolvedConflictWithRemoteRecord:(AWSCognitoConflict *)conflict { + return [[AWSCognitoResolvedConflict alloc] initWithRemoteRecord:conflict]; +} + ++ (instancetype) resolvedConflictWithLocalRecord:(AWSCognitoConflict *)conflict { + return [[AWSCognitoResolvedConflict alloc] initWithLocalRecord:conflict]; +} + ++ (instancetype) resolvedConflictWithValue:(AWSCognitoConflict *)conflict newValue:(NSString *)value { + return [[AWSCognitoResolvedConflict alloc] initWithValue:conflict newValue:value]; +} + +@end + diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.h new file mode 100644 index 00000000..f9b4e883 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.h @@ -0,0 +1,203 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "AWSCognitoHandlers.h" + +@class AWSCognitoRecord; +@class AWSTask; + +/** + An object that encapsulates the dataset metadata. + */ +@interface AWSCognitoDatasetMetadata : NSObject + +/** + The name of this dataset + */ +@property (nonatomic, readonly) NSString *name; +/** + The last sync count known on the client device. + */ +@property (nonatomic, readonly) NSNumber *lastSyncCount; +/** + The creation date of the dataset on the remote store. + */ +@property (nonatomic, readonly) NSDate *creationDate; +/** + The amount of storage on the remote store this dataset uses. + */ +@property (nonatomic, readonly) NSNumber *dataStorage; +/** + The id of the last device to modify this dataset. + */ +@property (nonatomic, readonly) NSString *lastModifiedBy; +/** + The date this dataset was last modified + */ +@property (nonatomic, readonly) NSDate *lastModifiedDate; +/** + The number of records in this dataset on the remote store. + */ +@property (nonatomic, readonly) NSNumber *numRecords; + +/** + Returns true if this dataset has been cleared locally, but not synchronized. + */ +- (BOOL)isDeleted; + +@end + +/** + An object that encapsulates the dataset. The dataset is the unit of sync + for Amazon Cognito. + */ +@interface AWSCognitoDataset : AWSCognitoDatasetMetadata + +/** + A conflict resolution handler that will receive calls when there is a + conflict during a sync operation. A conflict will occur when both remote and + local data have been updated since the last sync time. + When not explicitly set, we will use the default conflict resolution of + 'last writer wins', where the data most recently updated will be persisted. + */ +@property (nonatomic, copy) AWSCognitoRecordConflictHandler conflictHandler; + +/** + A deleted dataset handler. This handler will be called during a synchronization + when the remote service indicates that a dataset has been deleted. + Returning YES from the handler will cause the service to recreate the dataset + on the remote on the next synchronization. Returning NO or leaving this property + nil will cause the client to delete the dataset locally. + */ +@property (nonatomic, copy) AWSCognitoDatasetDeletedHandler datasetDeletedHandler; + +/** + A merged dataset handler. This handler will be called during a synchronization + when the remote service indicates that other datasets should be merged with this one. + Merged datasets should be fetched, their data overlayed locally and then removed. + Failing to implement this handler will result in merged datasets remaining on the + service indefinitely. + */ +@property (nonatomic, copy) AWSCognitoDatasetMergedHandler datasetMergedHandler; + +/** + The number of times to attempt a synchronization before failing. Defaults to + to the value on the AWSCognito client that opened this dataset. + */ +@property (nonatomic, assign) uint32_t synchronizeRetries; + +/** + Only synchronize if device is on a WiFi network. Defaults to + to the value on the AWSCognito client that opened this dataset. + */ +@property (nonatomic, assign) BOOL synchronizeOnWiFiOnly; + +/** + Sets a string object for the specified key in the dataset. + */ +- (void)setString:(NSString *) aString forKey:(NSString *) aKey; + +/** + Returns the string associated with the specified key. + */ +- (NSString *)stringForKey:(NSString *) aKey; + +/** + Synchronize local changes with remote changes on the service. First it pulls down changes from the service + and attempts to overlay them on the local store. Then it pushes any local updates to the service. If at any + point there is a conflict, conflict resolution is invoked. No changes are pushed to the service until + all conflicts are resolved. + */ +- (AWSTask *)synchronize; + +/** + Attempts to synchronize when device has connectivity. First it checks connectivity, if device is online + immediately invokes synchronize and returns the AWSTask associated with the attempt. If the device is offline, + schedules a synchronize for the next time the device comes online and returns a AWSTask with a nil result. + The scheduled synchronize is only valid for the lifecycle of the dataset object. The data will not be synchronized + if the app is exited before connectivity is regained. If you want to be notified when events occur during the + scheduled synchronize, you must add observers of the notifications found in AWSCognito + */ +- (AWSTask *)synchronizeOnConnectivity; + +/** + Subscribes this dataset to push notifications + + @return AWSTask with nil result. task.error will contain any errors. + */ +- (AWSTask *)subscribe; + +/** + Unsubscribes this dataset to push notifications + + @return AWSTask with nil result. task.error will contain any errors. + */ +- (AWSTask *)unsubscribe; + + +/** + Returns all of the records in the dataset. Will return deleted records. + + @return NSArray of AWSCognitoRecord objects + */ +- (NSArray *)getAllRecords; + +/** + Returns all the key value pairs in the dataset, ignore any deleted data. + + @return NSDictionary of all key value pairs. Contains no metadata. + */ +- (NSDictionary *)getAll; + +/** + Remove a record from the dataset. + + @param aKey the key to remove + */ +- (void)removeObjectForKey:(NSString *) aKey; + +/** + Returns the record associated with the specified key. + + @param aKey the key to return + + @return AWSCognitoRecord for this particular record. Will return nil if record does not exist. + */ +- (AWSCognitoRecord *)recordForKey:(NSString *) aKey; + +/** + Clear this dataset locally. Dataset will not be removed from the service until the next synchronize call. + */ +- (void) clear; + +/** + Returns the size in bytes for this dataset. + */ +- (long) size; + +/** + Returns the size in bytes for the specified key. + + @param aKey the key to check + */ +- (long) sizeForKey:(NSString *) aKey; + + + + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.m b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.m new file mode 100644 index 00000000..261f658b --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoDataset.m @@ -0,0 +1,849 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoDataset.h" +#import "AWSCognitoUtil.h" +#import "AWSCognitoConstants.h" +#import "AWSCognitoService.h" +#import "AWSCognitoRecord_Internal.h" +#import "AWSCognitoSQLiteManager.h" +#import "AWSCognitoConflict_Internal.h" +#import +#import "AWSCognitoRecord.h" +#import "AWSKSReachability.h" + +@interface AWSCognitoDatasetMetadata() + +@property (nonatomic, strong) NSString *name; +@property (nonatomic, strong) NSNumber *lastSyncCount; +@property (nonatomic, strong) NSDate *creationDate; +@property (nonatomic, strong) NSNumber *dataStorage; +@property (nonatomic, strong) NSString *lastModifiedBy; +@property (nonatomic, strong) NSDate *lastModifiedDate; +@property (nonatomic, strong) NSNumber *numRecords; +@end + +@implementation AWSCognitoDatasetMetadata + + +-(id)initWithDatasetName:(NSString *) datasetName dataSource:(AWSCognitoSQLiteManager *)manager { + [manager initializeDatasetTables:datasetName]; + if (self = [super init]) { + _name = datasetName; + [manager loadDatasetMetadata:self error:nil]; + } + return self; +} + +- (BOOL)isDeleted { + return [self.lastSyncCount intValue] == -1; +} + +@end + +@interface AWSCognitoDataset() +@property (nonatomic, strong) NSString *syncSessionToken; +@property (nonatomic, strong) AWSCognitoSQLiteManager *sqliteManager; + +@property (nonatomic, strong) AWSCognitoSync *cognitoService; + +@property (nonatomic, strong) AWSKSReachability *reachability; + +@property (nonatomic, strong) NSNumber *currentSyncCount; +@property (nonatomic, strong) NSDictionary *records; + +//for ensuring there is a maximum of 1 sync in flight and 1 pending sync +//to prevent unnecessary resource conflicts +@property (nonatomic, strong) dispatch_semaphore_t synchronizeQueue; +@property (nonatomic, strong) dispatch_semaphore_t serializer; + + +@end + +@implementation AWSCognitoDataset + + + +-(id)initWithDatasetName:(NSString *) datasetName + sqliteManager:(AWSCognitoSQLiteManager *)sqliteManager + cognitoService:(AWSCognitoSync *)cognitoService { + + if(self = [super initWithDatasetName:datasetName dataSource:sqliteManager]) { + _sqliteManager = sqliteManager; + _cognitoService = cognitoService; + _reachability = [AWSKSReachability reachabilityToHost:[cognitoService.configuration.endpoint.URL host]]; + _synchronizeQueue = dispatch_semaphore_create(2l); + _serializer = dispatch_semaphore_create(1l); + } + return self; +} + +-(void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - CRUD operations + +- (NSString *)stringForKey:(NSString *)aKey +{ + NSString *string = nil; + NSError *error = nil; + AWSCognitoRecord *record = [self getRecordById:aKey error:&error]; + if(error || (!record.data.string)) + { + AWSDDLogDebug(@"Error: %@", error); + } + + if (record != nil && ![record isDeleted]) { + string = record.data.string; + } + + return string; +} + +- (void)setString:(NSString *)aString forKey:(NSString *)aKey +{ + AWSCognitoRecordValue *data = [[AWSCognitoRecordValue alloc] initWithString:aString]; + AWSCognitoRecord *record = [self recordForKey:aKey]; + if (record == nil) { + record = [[AWSCognitoRecord alloc] initWithId:aKey data:data]; + } + else { + record.data = data; + } + + //do some limit checks + if([self sizeForRecord:record] > AWSCognitoMaxDatasetSize){ + AWSDDLogDebug(@"Error: Record would exceed max dataset size"); + return; + } + + if([self sizeForString:aKey] > AWSCognitoMaxKeySize){ + AWSDDLogDebug(@"Error: Key size too large, max is %d bytes", AWSCognitoMaxKeySize); + return; + } + + if([self sizeForString:aKey] < AWSCognitoMinKeySize){ + AWSDDLogDebug(@"Error: Key size too small, min is %d byte", AWSCognitoMinKeySize); + return; + } + + + if([self sizeForString:aString] > AWSCognitoMaxDatasetSize){ + AWSDDLogDebug(@"Error: Value size too large, max is %d bytes", AWSCognitoMaxRecordValueSize); + return; + } + + int numRecords = [[self.sqliteManager numRecords:self.name] intValue]; + + //if you have the max # of records and you aren't replacing an existing one + if(numRecords == AWSCognitoMaxNumRecords && !([self recordForKey:aKey] == nil)){ + AWSDDLogDebug(@"Error: Too many records, max is %d", AWSCognitoMaxNumRecords); + return; + } + + NSError *error = nil; + if(![self putRecord:record error:&error]) + { + AWSDDLogDebug(@"Error: %@", error); + } +} + +- (BOOL)putRecord:(AWSCognitoRecord *)record error:(NSError **)error +{ + if(record == nil || record.data == nil || record.recordId == nil) + { + if(error != nil) + { + *error = [AWSCognitoUtil errorIllegalArgument:@""]; + } + return NO; + } + + + + BOOL result = [self.sqliteManager putRecord:record datasetName:self.name error:error]; + if(result){ + self.lastModifiedDate = record.lastModified; + } + return result; +} + +- (AWSCognitoRecord *)recordForKey: (NSString *)aKey +{ + NSError *error = nil; + + AWSCognitoRecord * result = [self getRecordById:aKey error:&error]; + if(!result) + { + AWSDDLogDebug(@"Error: %@", error); + } + return result; +} + +- (AWSCognitoRecord *)getRecordById:(NSString *)recordId error:(NSError **)error +{ + if(recordId == nil) + { + if(error != nil) + { + *error = [AWSCognitoUtil errorIllegalArgument:@""]; + } + return nil; + } + + AWSCognitoRecord *fetchedRecord = [self.sqliteManager getRecordById:recordId + datasetName:(NSString *)self.name + error:error]; + + return fetchedRecord; +} + +- (BOOL)removeRecordById:(NSString *)recordId error:(NSError **)error +{ + if(recordId == nil) + { + if(error != nil) + { + *error = [AWSCognitoUtil errorIllegalArgument:@""]; + } + return NO; + } + + BOOL result = [self.sqliteManager flagRecordAsDeletedById:recordId + datasetName:(NSString *)self.name + error:error]; + + if(result){ + self.lastModifiedDate = [NSDate date]; + } + + return result; +} + +- (NSArray *)getAllRecords +{ + NSArray *allRecords = nil; + + allRecords = [self.sqliteManager allRecords:self.name]; + + return allRecords; +} + +- (NSDictionary *)getAll +{ + NSArray *allRecords = nil; + NSMutableDictionary *recordsAsDictionary = [NSMutableDictionary dictionary]; + + allRecords = [self.sqliteManager allRecords:self.name]; + for (AWSCognitoRecord *record in allRecords) { + if ([record isDeleted]) { + continue; + } + [recordsAsDictionary setObject:record.data.string forKey:record.recordId]; + } + + return recordsAsDictionary; +} + +- (void)removeObjectForKey:(NSString *)aKey +{ + NSError *error = nil; + if(![self removeRecordById:aKey error:&error]) + { + AWSDDLogDebug(@"Error: %@", error); + } +} + +- (void)clear +{ + NSError *error = nil; + if(![self.sqliteManager deleteDataset:self.name error:&error]) + { + AWSDDLogDebug(@"Error: %@", error); + } + else { + self.lastSyncCount = [NSNumber numberWithInt:-1]; + self.lastModifiedDate = [NSDate date]; + } +} + +#pragma mark - Size operations + +- (long) size { + NSArray * allRecords = [self getAllRecords]; + long size = 0; + if(allRecords != nil){ + for (AWSCognitoRecord *record in allRecords) { + size += [self sizeForRecord:record]; + } + } + return size; +} + +- (long) sizeForKey: (NSString *) aKey { + return [self sizeForRecord:[self recordForKey:aKey]]; +} + +- (long) sizeForRecord:(AWSCognitoRecord *) aRecord { + if(aRecord == nil){ + return 0; + } + + //get the size of the key + long sizeOfKey = [self sizeForString:aRecord.recordId]; + + //if it has been deleted, just return the size of the key + if ([aRecord isDeleted]) { + return sizeOfKey; + } + + //return size of key + size of value + return sizeOfKey + [self sizeForString:aRecord.data.string]; +} + +- (long) sizeForString:(NSString *) aString{ + if(aString == nil){ + return 0; + } + return [aString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; +} + + +#pragma mark - Synchronize + +/** + * The pull part of our sync + * 1. Do a list records, overlay changes + * 2. Resolve conflicts + */ +- (AWSTask *)syncPull:(uint32_t)remainingAttempts { + + //list records that have changed since last sync + AWSCognitoSyncListRecordsRequest *request = [AWSCognitoSyncListRecordsRequest new]; + request.identityPoolId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityPoolId; + request.identityId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityId; + request.datasetName = self.name; + request.lastSyncCount = self.currentSyncCount; + request.syncSessionToken = self.syncSessionToken; + + self.lastSyncCount = self.currentSyncCount; + + return [[self.cognitoService listRecords:request] continueWithBlock:^id(AWSTask *task) { + if (task.isCancelled) { + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + }else if(task.error){ + AWSDDLogError(@"Unable to list records: %@", task.error); + //decrement sync counts that exceed the service sync count and try again + if(task.error.code == AWSCognitoSyncErrorInvalidParameter && self.currentSyncCount.longLongValue > 0 + && task.error.userInfo[@"NSLocalizedDescription"] && [task.error.userInfo[@"NSLocalizedDescription"] hasPrefix:@"No such SyncCount:"]){ + self.currentSyncCount = [NSNumber numberWithLongLong:self.currentSyncCount.longLongValue - 1]; + return [self syncPull:remainingAttempts-1]; + } else { + return task; + } + }else { + NSError *error = nil; + NSMutableArray *conflicts = [NSMutableArray new]; + // collect updates to write in a transaction + NSMutableArray *nonConflictRecords = [NSMutableArray new]; + NSMutableArray *existingRecords = [NSMutableArray new]; + // keep track of record names for notificaiton + NSMutableArray *changedRecordNames = [NSMutableArray new]; + AWSCognitoSyncListRecordsResponse *response = task.result; + self.syncSessionToken = response.syncSessionToken; + + // check the response if dataset is present. If not and we have + // a local sync count, the dataset was deleted. + // Also check to see if the dataset was deleted and recreated + // sinc our last sync + if ((self.lastSyncCount != 0 && ![response.datasetExists boolValue]) || + ([response.datasetDeletedAfterRequestedSyncCount boolValue])) { + + // if the developer has implemented the handler, call it + // and if they return NO, we clear data, otherwise we assume the + // dataset should be recreated + if (self.datasetDeletedHandler && !self.datasetDeletedHandler(self.name)) { + // delete the record data + [self.sqliteManager deleteDataset:self.name error:nil]; + + // if the dataset doesn't exist on the remote, clear the + // metadata and return. The push will be a no-op + if (![response.datasetExists boolValue]) { + [self.sqliteManager deleteMetadata:self.name error:nil]; + return nil; + } + } + [self.sqliteManager resetSyncCount:self.name error:nil]; + self.lastSyncCount = 0; + self.currentSyncCount = 0; + } + + // check the response for merged datasets, call the appropriate handler + if (response.mergedDatasetNames && response.mergedDatasetNames.count > 0 && self.datasetMergedHandler) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + self.datasetMergedHandler(self.name, response.mergedDatasetNames); + }); + } + + if(response.records){ + // get the dataset sync count for updating the last sync count + self.lastSyncCount = response.datasetSyncCount; + for(AWSCognitoSyncRecord *record in response.records){ + [existingRecords addObject:record.key]; + [changedRecordNames addObject:record.key]; + + //overlay local with remote if local isn't dirty + AWSCognitoRecord * existing = [self.sqliteManager getRecordById:record.key datasetName:self.name error:&error]; + + AWSCognitoRecordValueType recordType = AWSCognitoRecordValueTypeString; + if (record.value == nil) { + recordType = AWSCognitoRecordValueTypeDeleted; + } + AWSCognitoRecord * newRecord = [[AWSCognitoRecord alloc] initWithId:record.key data:[[AWSCognitoRecordValue alloc]initWithString:record.value type:recordType]]; + newRecord.syncCount = [record.syncCount longLongValue]; + newRecord.lastModifiedBy = record.lastModifiedBy; + newRecord.lastModified = record.lastModifiedDate; + if(newRecord.lastModifiedBy == nil){ + newRecord.lastModifiedBy = @"Unknown"; + } + + // separate conflicts from non-conflicts + if(!existing || existing.isDirty==NO || [existing.data.string isEqualToString:record.value]){ + [nonConflictRecords addObject: [[AWSCognitoRecordTuple alloc] initWithLocalRecord:existing remoteRecord:newRecord]]; + } + else{ + //conflict resolution + AWSDDLogInfo(@"Record %@ is dirty with value: %@ and can't be overwritten, flagging for conflict resolution",existing.recordId,existing.data.string); + [conflicts addObject: [[AWSCognitoConflict alloc] initWithLocalRecord:existing remoteRecord:newRecord]]; + } + } + + NSMutableArray *resolvedConflicts = [NSMutableArray arrayWithCapacity:[conflicts count]]; + //if there are conflicts start conflict resolution + if([conflicts count] > 0){ + if(self.conflictHandler == nil) { + self.conflictHandler = [AWSCognito defaultConflictHandler]; + } + + for (AWSCognitoConflict *conflict in conflicts) { + AWSCognitoResolvedConflict *resolved = self.conflictHandler(self.name,conflict); + + // no resolution to conflict abort synchronization + if (resolved == nil) { + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + + [resolvedConflicts addObject:resolved]; + } + } + + if (nonConflictRecords.count > 0 || resolvedConflicts.count > 0) { + // attempt to write all remote changes + if([self.sqliteManager updateWithRemoteChanges:self.name nonConflicts:nonConflictRecords resolvedConflicts:resolvedConflicts error:&error]) { + // successfully wrote data, notify interested parties + [self postDidChangeLocalValueFromRemoteNotification:changedRecordNames]; + } + else { + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + } + + // update our local sync count + if(self.currentSyncCount < self.lastSyncCount){ + [self.sqliteManager updateLastSyncCount:self.name syncCount:self.lastSyncCount lastModifiedBy:response.lastModifiedBy]; + } + + } + } + + return nil; + }]; + +} + + +/** + * The push part of the sync + * 1. Write any changes to remote + * 2. Restart sync if errors occur + */ +- (AWSTask *)syncPush:(uint32_t)remainingAttempts { + + //if there are no pending conflicts + NSMutableArray *patches = [NSMutableArray new]; + NSError *error = nil; + self.records = [self.sqliteManager recordsUpdatedAfterLastSync:self.name error:&error]; + NSNumber* maxPatchSyncCount = [NSNumber numberWithLongLong:0L]; + + //collect local changes + for(AWSCognitoRecord *record in self.records.allValues){ + AWSCognitoSyncRecordPatch *patch = [AWSCognitoSyncRecordPatch new]; + patch.key = record.recordId; + patch.syncCount = [NSNumber numberWithLongLong: record.syncCount]; + patch.value = record.data.string; + patch.op = [record isDeleted]?AWSCognitoSyncOperationRemove : AWSCognitoSyncOperationReplace; + [patches addObject:patch]; + + //track the max sync count + if([patch.syncCount longLongValue] > [maxPatchSyncCount longLongValue]){ + maxPatchSyncCount = patch.syncCount; + } + } + + // if there were local changes + if([patches count] > 0){ + // don't push local changes if they are guaranteed to fail due to dataset size + if([self size] > AWSCognitoMaxDatasetSize){ + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorUserDataSizeLimitExceeded userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + + AWSCognitoSyncUpdateRecordsRequest *request = [AWSCognitoSyncUpdateRecordsRequest new]; + request.identityId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityId; + request.identityPoolId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityPoolId; + request.datasetName = self.name; + request.recordPatches = patches; + request.syncSessionToken = self.syncSessionToken; + request.deviceId = [AWSCognito cognitoDeviceId]; + return [[self.cognitoService updateRecords:request] continueWithBlock:^id(AWSTask *task) { + NSNumber * currentSyncCount = self.lastSyncCount; + BOOL okToUpdateSyncCount = YES; + if(task.isCancelled){ + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + }else if(task.error){ + if(task.error.code == AWSCognitoSyncErrorResourceConflict){ + AWSDDLogInfo(@"Conflicts existed on update, restarting synchronize."); + if(currentSyncCount > maxPatchSyncCount) { + //it's possible there is a local dirty record with a stale sync count + //this will fix it + [self.sqliteManager updateLastSyncCount:self.name syncCount:maxPatchSyncCount lastModifiedBy:nil]; + } + return [self synchronizeInternal:remainingAttempts-1]; + } + else { + AWSDDLogError(@"An error occured attempting to update records: %@",task.error); + } + return task; + }else{ + AWSCognitoSyncUpdateRecordsResponse * response = task.result; + if(response.records) { + NSMutableArray *changedRecords = [NSMutableArray new]; + NSMutableArray *changedRecordsNames = [NSMutableArray new]; + NSNumber *maxSyncCount = [NSNumber numberWithLong:0]; + for (AWSCognitoSyncRecord * record in response.records) { + [changedRecordsNames addObject:record.key]; + AWSCognitoRecordValueType recordType = AWSCognitoRecordValueTypeString; + if (record.value == nil) { + recordType = AWSCognitoRecordValueTypeDeleted; + } + AWSCognitoRecord * newRecord = [[AWSCognitoRecord alloc] initWithId:record.key data:[[AWSCognitoRecordValue alloc]initWithString:record.value type:recordType]]; + + // Check to see if the sync count on the result is only one more than our current sync + // count. This means that we were the only update and we can safely fastforward + // If not, we'll keep sync count the same so we pull down updates that occurred between + // push and pull. + if(record.syncCount.longLongValue > currentSyncCount.longLongValue + 1){ + okToUpdateSyncCount = NO; + } + + // keep track of the max sync count returned by the service + if(record.syncCount.longLongValue > maxSyncCount.longLongValue) { + maxSyncCount = record.syncCount; + } + + newRecord.syncCount = [record.syncCount longLongValue]; + newRecord.dirtyCount = 0; + newRecord.lastModifiedBy = record.lastModifiedBy; + if(newRecord.lastModifiedBy == nil){ + newRecord.lastModifiedBy = @"Unknown"; + } + newRecord.lastModified = record.lastModifiedDate; + + AWSCognitoRecord * existingRecord = [self.records objectForKey:record.key]; + if(existingRecord == nil){ + //this means we got an update returned by the server that we didn't cause + //i.e. based on some updates, the lambda function run server side inserted + //a brand new key unrelated to our patches into our dataset. + //get the current value of that key from our dataset if it exists + //and overwrite it with what was returned from the server + NSError *error = nil; + existingRecord = [self.sqliteManager getRecordById:record.key datasetName:self.name error:&error]; + } + + [changedRecords addObject:[[AWSCognitoRecordTuple alloc] initWithLocalRecord:existingRecord remoteRecord:newRecord]]; + } + NSError *error = nil; + if([self.sqliteManager updateLocalRecordMetadata:self.name records:changedRecords error:&error]) { + // successfully wrote the update notify interested parties + [self postDidChangeRemoteValueNotification:changedRecordsNames]; + if(okToUpdateSyncCount){ + //if we only increased the sync count by 1, fast forward the last sync count to our update sync count + [self.sqliteManager updateLastSyncCount:self.name syncCount:maxSyncCount lastModifiedBy:nil]; + } + } else { + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + } + } + return nil; + }]; + } + return nil; +} + +- (AWSTask *)synchronize { + // ensure necessary network is available + if(self.synchronizeOnWiFiOnly && self.reachability.WWANOnly){ + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorWiFiNotAvailable userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + + [self postDidStartSynchronizeNotification]; + + [self checkForLocalMergedDatasets]; + + AWSCognitoCredentialsProvider *cognitoCredentials = self.cognitoService.configuration.credentialsProvider; + return [[[cognitoCredentials credentials] continueWithBlock:^id(AWSTask *task) { + NSError * error = nil; + if (task.error) { + error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoAuthenticationFailed userInfo:nil]; + } + //only allow one sync to be pending and one in flight at a time + else if(!dispatch_semaphore_wait(self.synchronizeQueue, DISPATCH_TIME_NOW)){ + //only allow one thread to synchronize data at a time, wait a max of 5 minutes for the in flight + //sync to complete. Because this may block the main thread, run on a background thread + AWSTaskCompletionSource *completion = [AWSTaskCompletionSource new]; + dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + if(!dispatch_semaphore_wait(self.serializer, dispatch_time(DISPATCH_TIME_NOW, 300 * NSEC_PER_SEC))){ + self.syncSessionToken = nil; + [[self synchronizeInternal:self.synchronizeRetries] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + dispatch_semaphore_signal(self.serializer); + dispatch_semaphore_signal(self.synchronizeQueue); + if(task.error){ + completion.error = task.error; + }else { + completion.result = task.result; + } + return task; + }]; + }else { + dispatch_semaphore_signal(self.synchronizeQueue); + completion.error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTimedOutWaitingForInFlightSync userInfo:nil]; + } + }); + return completion.task; + }else { + error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorSyncAlreadyPending userInfo:nil]; + } + + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + }] continueWithBlock:^id(AWSTask *task) { + [self postDidEndSynchronizeNotification]; + return task; + }]; +} + +- (AWSTask *)synchronizeInternal:(uint32_t)remainingAttempts { + if(remainingAttempts == 0){ + AWSDDLogError(@"Conflict retries exhausted"); + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorConflictRetriesExhausted userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } + + //used for determining if we can fast forward the last sync count after update + self.currentSyncCount = [self.sqliteManager lastSyncCount:self.name]; + + //delete the dataset if it no longer exists + if([self.currentSyncCount intValue] == -1){ + AWSCognitoSyncDeleteDatasetRequest *request = [AWSCognitoSyncDeleteDatasetRequest new]; + request.identityPoolId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityPoolId; + request.identityId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityId; + request.datasetName = self.name; + return [[self.cognitoService deleteDataset:request]continueWithBlock:^id(AWSTask *task) { + if(task.isCancelled) { + NSError *error = [NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]; + [self postDidFailToSynchronizeNotification:error]; + return [AWSTask taskWithError:error]; + } else if(task.error && task.error.code != AWSCognitoSyncErrorResourceNotFound){ + AWSDDLogError(@"Unable to delete dataset: %@", task.error); + return task; + } else { + [self.sqliteManager deleteMetadata:self.name error:nil]; + return nil; + } + }]; + } + + return [[self syncPull:remainingAttempts] continueWithSuccessBlock:^id(AWSTask *task) { + return [self syncPush:remainingAttempts]; + }]; +} + +- (AWSTask *)synchronizeOnConnectivity { + //if we are out of connectivity or we are on wwan and wifi is required, perform sync when + //necessary reachability is achieved + if(!self.reachability.reachable || (self.reachability.WWANOnly && self.synchronizeOnWiFiOnly)){ + AWSTaskCompletionSource* completionSource = [AWSTaskCompletionSource taskCompletionSource]; + [AWSKSReachableOperation operationWithReachability:self.reachability allowWWAN:!self.synchronizeOnWiFiOnly onReachabilityAchieved:^{ + __weak AWSCognitoDataset* weakSelf = self; + [[weakSelf synchronize] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + completionSource.result = task; + return task; + }]; + }]; + return completionSource.task; + } + //else perform sync + else{ + return [self synchronize]; + } +} + +-(AWSTask *)subscribe { + NSString *currentDeviceId = [AWSCognito cognitoDeviceId]; + + if(!currentDeviceId){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorDeviceNotRegistered userInfo:nil]]; + } + + AWSCognitoSyncSubscribeToDatasetRequest* request = [AWSCognitoSyncSubscribeToDatasetRequest new]; + request.identityPoolId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityPoolId; + request.identityId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityId; + request.datasetName = self.name; + request.deviceId = currentDeviceId; + return [[self.cognitoService subscribeToDataset:request] continueWithBlock:^id(AWSTask *task) { + if(task.isCancelled){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]]; + }else if(task.error){ + AWSDDLogError(@"Unable to subscribe dataset: %@", task.error); + return task; + }else { + return [AWSTask taskWithResult:task.result]; + } + }]; +} + +-(AWSTask *)unsubscribe { + NSString *currentDeviceId = [AWSCognito cognitoDeviceId]; + + if(!currentDeviceId){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorDeviceNotRegistered userInfo:nil]]; + } + + AWSCognitoSyncUnsubscribeFromDatasetRequest* request = [AWSCognitoSyncUnsubscribeFromDatasetRequest new]; + request.identityPoolId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityPoolId; + request.identityId = ((AWSCognitoCredentialsProvider *)self.cognitoService.configuration.credentialsProvider).identityId; + request.datasetName = self.name; + request.deviceId = currentDeviceId; + return [[self.cognitoService unsubscribeFromDataset:request] continueWithBlock:^id(AWSTask *task) { + if(task.isCancelled){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]]; + }else if(task.error){ + AWSDDLogError(@"Unable to unsubscribe dataset: %@", task.error); + return task; + }else { + return [AWSTask taskWithResult:task.result]; + } + }]; +} + +#pragma mark IdentityMerge + +- (void)identityChanged:(NSNotification *)notification { + AWSDDLogDebug(@"IdentityChanged"); + + // by the point we are called, all datasets will have been reparented + [self checkForLocalMergedDatasets]; +} + +- (void) checkForLocalMergedDatasets { + if (self.datasetMergedHandler) { + // check if we have any local merge datasets + NSArray *localMergeDatasets = [self.sqliteManager getMergeDatasets:self.name error:nil]; + if (localMergeDatasets) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + self.datasetMergedHandler(self.name, localMergeDatasets); + }); + } + } +} + +#pragma mark Notifications + +- (void)postDidStartSynchronizeNotification +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoDidStartSynchronizeNotification + object:self + userInfo:@{@"dataset": self.name}]; + }); +} + +- (void)postDidEndSynchronizeNotification +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoDidEndSynchronizeNotification + object:self + userInfo:@{@"dataset": self.name}]; + }); +} + +- (void)postDidChangeLocalValueFromRemoteNotification:(NSArray *)changedValues +{ + self.lastModifiedDate = [NSDate date]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoDidChangeLocalValueFromRemoteNotification + object:self + userInfo:@{@"dataset": self.name, + @"keys": changedValues}]; + }); +} + +- (void)postDidChangeRemoteValueNotification:(NSArray *)changedValues +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoDidChangeRemoteValueNotification + object:self + userInfo:@{@"dataset": self.name, + @"keys": changedValues}]; + }); +} + +- (void)postDidFailToSynchronizeNotification:(NSError *)error +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoDidFailToSynchronizeNotification + object:self + userInfo:@{@"dataset": self.name, + @"error": error}]; + }); +} + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoHandlers.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoHandlers.h new file mode 100644 index 00000000..4690f01f --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoHandlers.h @@ -0,0 +1,50 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class AWSCognitoResolvedConflict; +@class AWSCognitoConflict; + +/** + DatasetDeletedHandler + + @param datasetName The name of the dataset that was deleted + + @return YES if Cognito should recreate the dataset, NO if Cognito should delete + the local copy of the dataset. + */ +typedef BOOL (^AWSCognitoDatasetDeletedHandler)(NSString *datasetName); + +/** + DatasetMergedHandler + + @param datasetName The name of the local dataset that is the destination of the merge + @param datasets The list of dataset names that should be merged into the destination + */ +typedef void (^AWSCognitoDatasetMergedHandler)(NSString *datasetName, NSArray *datasets); + +/** + ConflictHandler + + @param conflict The AWSCognitoConflict for this record. Conflict contains + both local and remote data as properties. + + @return An instance of AWSCognitoResolvedConflict which indicates what data should be + stored and syncronized. Returning nil will cancel synchronization. + */ +typedef AWSCognitoResolvedConflict* (^AWSCognitoRecordConflictHandler)(NSString *datasetName, AWSCognitoConflict *conflict); diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.h new file mode 100644 index 00000000..c159e7dd --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.h @@ -0,0 +1,133 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +typedef NS_ENUM(NSInteger, AWSCognitoRecordValueType) { + AWSCognitoRecordValueTypeUnknown, + AWSCognitoRecordValueTypeString, + AWSCognitoRecordValueTypeDeleted, +}; + +/** + An object that encapsulates the record value. + */ +@interface AWSCognitoRecordValue : NSObject + + +/** + The type of the record value. + + The record value datatypes. +
    +
  • AWSCognitoRecordValueTypeUnknown - Unknown type.
  • +
  • AWSCognitoRecordValueTypeString - The string value.
  • +
  • AWSCognitoRecordValueTypeDeleted - A deleted value.
  • +
+ */ +@property (nonatomic, readonly) AWSCognitoRecordValueType type; + +/** + Initializes a AWSCognitoRecordValue with the given string value. + The type property is automatically set to AWSCognitoRecordValueTypeString. + + @param value The string value of the AWSCognitoRecordValue. + + @return The initialized instance + */ +- (instancetype)initWithString:(NSString *)value; + +/** + Returns the string value. + + @return The string value stored by the record value object. + */ +- (NSString *)string; + +@end + +@interface AWSCognitoRecordMetadata : NSObject + +/** + Record ID or name. + */ +@property (nonatomic, readonly) NSString *recordId; + +/** + The last date the record was modified. + */ +@property (nonatomic, readonly) NSDate *lastModified; + +/** + The ID of the client that last modified the record. Set in AWSCognitoConfig under the clientID property. + */ +@property (nonatomic, strong) NSString *lastModifiedBy; + +/** + Boolean indicating whether or not the record has updates/deletes that need to be synced with the server. + */ +@property (nonatomic, readonly, getter = isDirty) BOOL dirty; + +/** + Integer value indicating how many times the record has been written since the last sync. + The value is 0 if the record has not been modified. The value is incremented by 1 each time the record is updated. + The value is set to -1 when the record is marked as deleted from the local database. + */ +@property (nonatomic, assign) int64_t dirtyCount; + +/** + Integer value of the server sync count of the record. + */ +@property (nonatomic, assign) int64_t syncCount; + +- (instancetype)initWithId:(NSString *)recordId; + +/** + Checks if the metadata matches. + + @param object The object to be compared to the receiver. + May be nil, in which case this method returns NO. + @return YES if the receiver and object have equal metadata, otherwise NO. + */ +- (BOOL)isEqualMetadata:(id)object; + +@end + +@interface AWSCognitoRecord : AWSCognitoRecordMetadata + +/** + The data for the record. + */ +@property (nonatomic, strong) AWSCognitoRecordValue *data; + +/** + Initializes a AWSCognitoRecord with the given recordID, given data, and a dirtyCount and recordVersion of 0. + + @param recordId The record ID of the AWSCognitoRecord + @param data the initial data that the AWSCognitoRecord will contain + */ +- (instancetype)initWithId:(NSString *)recordId + data:(AWSCognitoRecordValue *)data; + +/** + Returns true if this record has been deleted + + @return YES if the record is deleted, NO otherwise + */ +- (BOOL)isDeleted; + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.m b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.m new file mode 100644 index 00000000..39131e17 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoRecord.m @@ -0,0 +1,338 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoService.h" +#import "AWSCognitoRecord.h" +#import "AWSCognitoUtil.h" +#import "AWSCognitoConstants.h" +#import "AWSCognitoRecord_Internal.h" + +@implementation AWSCognitoRecordMetadata + +- (instancetype)initWithId:(NSString *)recordId { + if (self = [super init]) { + _recordId = recordId; + } + return self; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary +{ + self = [super init]; + if (nil != self) { + NSString *value = nil; + + value = [dictionary objectForKey:AWSCognitoTableRecordKeyName]; + _recordId = value; + + value = [dictionary objectForKey:AWSCognitoLastModifiedFieldName]; + _lastModified = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:[value longLongValue]]]; + + value = [dictionary objectForKey:AWSCognitoModifiedByFieldName]; + _lastModifiedBy = value; + + value = [dictionary objectForKey:AWSCognitoDirtyFieldName]; + _dirtyCount = [value longLongValue]; + + value = [dictionary objectForKey:AWSCognitoSyncCountFieldName]; + _syncCount = [value longLongValue]; + } + return self; +} + +- (BOOL)isEqualMetadata:(id)object +{ + if([object isKindOfClass:[AWSCognitoRecordMetadata class]]) + { + return NO; + } + + AWSCognitoRecordMetadata *other = object; + if (self.syncCount != other.syncCount) { + return NO; + } + + if (self.dirtyCount != other.dirtyCount) { + return NO; + } + + if (![self.recordId isEqualToString:other.recordId]) { + return NO; + } + + if (![self.lastModifiedBy isEqualToString:other.lastModifiedBy]) { + return NO; + } + + if ([self.lastModified compare:other.lastModified] != NSOrderedSame) { + return NO; + } + + return YES; +} + +@end + +@implementation AWSCognitoRecord + +- (instancetype)initWithId:(NSString *)recordId + data:(AWSCognitoRecordValue *)data { + self = [super initWithId:recordId]; + if (nil != self) { + _data = data; + } + return self; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary +{ + self = [super initWithDictionary:dictionary]; + + if (nil != self) { + _data = [[AWSCognitoRecordValue alloc] initWithString:[dictionary objectForKey:AWSCognitoRecordValueName]]; + } + return self; +} + +- (BOOL)isEqual:(id)object +{ + if(![self isEqualMetadata:object]) + { + return NO; + } + + AWSCognitoRecord *other = object; + if (![[self.data toJsonString] isEqualToString:[other.data toJsonString]]) { + return NO; + } + + return YES; +} + +- (NSDictionary *)dictionaryRepresentation +{ + + NSString *lastModifiedValue = [NSString stringWithFormat:@"%lld", [AWSCognitoUtil getTimeMillisForDate:self.lastModified]]; + + + NSString *recordVersionValue= [NSString stringWithFormat:@"%lld", self.syncCount]; + + NSString *recordTypeValue = [NSString stringWithFormat:@"%ld", (long)self.data.type]; + + return [NSDictionary dictionaryWithObjectsAndKeys: + self.recordId, AWSCognitoTableRecordKeyName, + lastModifiedValue, AWSCognitoLastModifiedFieldName, + self.data.string, AWSCognitoRecordValueName, + recordTypeValue, AWSCognitoTypeFieldName, + self.lastModifiedBy, AWSCognitoModifiedByFieldName, + recordVersionValue, AWSCognitoSyncCountFieldName, nil]; +} + +- (AWSCognitoRecord *)copyForFlush +{ + AWSCognitoRecord *flushableCopy = [[AWSCognitoRecord alloc] initWithId:self.recordId data:self.data]; + flushableCopy.lastModified = self.lastModified; + flushableCopy.lastModifiedBy = self.lastModifiedBy; + flushableCopy.syncCount = self.syncCount; + flushableCopy.dirtyCount = 0; + + return flushableCopy; +} + +- (AWSCognitoRecord *)copy +{ + AWSCognitoRecord *copy = [[AWSCognitoRecord alloc] initWithId:self.recordId data:self.data]; + copy.lastModified = self.lastModified; + copy.lastModifiedBy = self.lastModifiedBy; + copy.syncCount = self.syncCount; + copy.dirtyCount = self.dirtyCount; + + return copy; +} + +- (BOOL)isDirty +{ + return self.dirtyCount != 0; +} + +- (BOOL)isDeleted { + return self.data.type == AWSCognitoRecordValueTypeDeleted; +} + +- (NSString *)description +{ + NSMutableString *buffer = [NSMutableString new]; + + [buffer appendString:[super description]]; + + [buffer appendFormat:@"recordId: %@\n", self.recordId]; + [buffer appendFormat:@"lastModified: %@\n", self.lastModified]; + [buffer appendFormat:@"data: %@\n", self.data]; + [buffer appendFormat:@"lastModifiedBy: %@\n", self.lastModifiedBy]; + [buffer appendFormat:@"dirtyCount: %lld\n", self.dirtyCount]; + [buffer appendFormat:@"recordVersion: %lld\n", self.syncCount]; + + return [NSString stringWithString:buffer]; +} + +@end + +@implementation AWSCognitoRecordValue + +#pragma mark - Init methods + +- (instancetype)init { + if(self = [super init]) { + _type = AWSCognitoRecordValueTypeUnknown; + } + + return self; +} + +- (instancetype)initWithString:(NSString *)value { + return [self initWithString:value type:AWSCognitoRecordValueTypeString]; +} + +#pragma mark - Private init methods +- (instancetype)initWithJson:(NSString *)json + type:(AWSCognitoRecordValueType)type { + if(json == nil){ + return [self initWithString:nil type:type]; + } + NSError *error; + NSObject *value = [[NSJSONSerialization + JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingMutableContainers + error:&error] objectForKey:AWSCognitoDataFieldKeyName]; + NSString *stringValue = nil; + + switch (type) { + case AWSCognitoRecordValueTypeString: + stringValue = (NSString *)value; + break; + default: + NSAssert(YES,@"Type: %lld is unsupported for this initializer", (long long)type); + break; + } + return [self initWithString:stringValue type:type]; + +} + +- (instancetype)initWithString:(NSString *)value + type:(AWSCognitoRecordValueType)type +{ + if(self = [super init]) + { + _type = type; + switch (type) { + case AWSCognitoRecordValueTypeString: + _stringValue = value; + break; + case AWSCognitoRecordValueTypeDeleted: + _stringValue = AWSCognitoDeletedRecord; + break; + default: + NSAssert(YES,@"Type: %lld is unsupported for this initializer", (long long)type); + break; + } + } + + return self; +} +#pragma mark - Getters + +- (NSString *)string +{ + if(self.type == AWSCognitoRecordValueTypeString) + { + return (NSString *)self.stringValue; + } + + return nil; +} + +#pragma mark json +- (NSString *)toJsonString +{ + if(self.stringValue == nil) + return nil; + + NSObject * value = nil; + switch (self.type) { + + case AWSCognitoRecordValueTypeString: + value = self.stringValue; + break; + case AWSCognitoRecordValueTypeDeleted: + value = AWSCognitoDeletedRecord; + break; + default: + NSAssert(YES,@"Type: %lld is unsupported for this method", (long long)self.type); + break; + } + + if(value != nil){ + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject: [NSDictionary dictionaryWithObjectsAndKeys: + value, AWSCognitoDataFieldKeyName, nil] + options:0 error:&error]; + if(jsonData != nil){ + return [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding]; + } + } + return nil; +} + +#pragma mark - + +- (BOOL)isEqual:(id)object { + if([object isKindOfClass:[AWSCognitoRecordValue class]]) { + AWSCognitoRecordValue *recordValue = object; + if(recordValue.type == self.type) { + switch (self.type) { + case AWSCognitoRecordValueTypeString: + if([recordValue.string isEqualToString:self.string]) { + return YES; + } + break; + + case AWSCognitoRecordValueTypeDeleted: + return YES; + break; + default: + break; + } + } + } + + return NO; +} + +- (NSString *)description +{ + NSMutableString *buffer = [NSMutableString new]; + + [buffer appendString:[super description]]; + + [buffer appendFormat:@"\nType: %lld\n", (long long)self.type]; + [buffer appendFormat:@"Value: %@", self.stringValue]; + + return [NSString stringWithString:buffer]; +} + +@end + diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.h b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.h new file mode 100644 index 00000000..b353830f --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.h @@ -0,0 +1,396 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import +#import +#import "AWSCognitoHandlers.h" +#import "AWSCognitoSyncService.h" + +NS_ASSUME_NONNULL_BEGIN + +@class AWSCognitoDataset; +@class AWSCognitoDatasetMetadata; +@class AWSCognitoCredentialsProvider; +@class AWSTask; + +@interface AWSCognito : AWSService + +/** + Posted when the synchronization is started. + The notification sender is an instance of AWSCognitoClient. The userInfo + contains the dataset name. + @discussion This notification is posted once per synchronization. + The notification is posted on the Grand Central Dispatch + DISPATCH_QUEUE_PRIORITY_DEFAULT queue. The user interface should not be + modified on the thread. + */ +extern NSString *const AWSCognitoDidStartSynchronizeNotification; +/** + Posted when the synchronization is finished with or without errors. + The notification sender is an instance of AWSCognitoClient. The userInfo + contains the dataset name. + @discussion This notification is posted once per synchronization. + The notification is posted on the Grand Central Dispatch + DISPATCH_QUEUE_PRIORITY_DEFAULT queue. The user interface should not be + modified on the thread. + */ +extern NSString *const AWSCognitoDidEndSynchronizeNotification; +/** + Posted when values are changed to the value from the remote data store. The notification + sender is an instance of AWSCognitoClient. The userInfo contains the dataset name and + an NSArray of changed keys. + @discussion This notification may be posted multiple times per synchronization. + The notification is posted on the Grand Central Dispatch + DISPATCH_QUEUE_PRIORITY_DEFAULT queue. The user interface should not be + modified on the thread. + */ +extern NSString *const AWSCognitoDidChangeLocalValueFromRemoteNotification; +/** + Posted when locally changed values are pushed to the remote store. The notification + sender is an instance of AWSCognitoClient. The userInfo contains the dataset name and + an NSArray of changed keys. + @discussion This notification may be posted multiple times per synchronization. + The notification is posted on the Grand Central Dispatch + DISPATCH_QUEUE_PRIORITY_DEFAULT queue. The user interface should not be + modified on the thread. + */ +extern NSString *const AWSCognitoDidChangeRemoteValueNotification; +/** + Posted when the synchronization for the for the dataset failed. The notification + sender is an instance of AWSCognitoClient. The userInfo contains the dataset name + and error. + @discussion This notification may be posted multiple times per synchronization. + The notification is posted on the Grand Central Dispatch + DISPATCH_QUEUE_PRIORITY_DEFAULT queue. The user interface should not be + modified on the thread. + */ +extern NSString *const AWSCognitoDidFailToSynchronizeNotification; + +/** + The error domain for AWSCognito errors. +
    +
  • AWSCognitoErrorUnknown - Unknow error.
  • +
  • AWSCognitoErrorRemoteDataStorageFailed - The Amazon Cognito call temporarily failed.
  • +
  • AWSCognitoErrorInvalidDataValue - The Amazon Cognito call failed. The value for the + key is invalid and has been deleted from the local database.
  • +
  • AWSCognitoErrorDataSizeLimitExceeded - The Amazon Cognito call failed. A + dataset has exceeded the max dataset size.
  • +
  • AWSCognitoErrorLocalDataStorageFailed - The SQLite call failed.
  • +
  • AWSCognitoErrorIllegalArgument - The input value is invalid.
  • +
  • AWSCognitoErrorConflictRetriesExhausted - The number of attempts to resolve a conflict + has exceeded the max number of retries.
  • +
  • AWSCognitoErrorWiFiNotAvailable - WiFi is required and not currently available.
  • +
  • AWSCognitoErrorDeviceNotRegistered - The device has not been registered yet.
  • +
  • AWSCognitoErrorSyncAlreadyPending - This sync is unecessary, there is already a pending sync.
  • +
  • AWSCognitoErrorTimedOutWaitingForInFlightSync - There is a in flight sync that took over 5 minutes to complete, so this one was cancelled.
  • +
+ */ +FOUNDATION_EXPORT NSString *const AWSCognitoErrorDomain; +typedef NS_ENUM(NSInteger, AWSCognitoErrorType) { + AWSCognitoErrorUnknown = 0, + AWSCognitoErrorRemoteDataStorageFailed = -1000, + AWSCognitoErrorInvalidDataValue = -1001, + AWSCognitoErrorUserDataSizeLimitExceeded = -1002, + AWSCognitoErrorLocalDataStorageFailed = -2000, + AWSCognitoErrorIllegalArgument = -3000, + AWSCognitoAuthenticationFailed = -4000, + AWSCognitoErrorTaskCanceled = -5000, + AWSCognitoErrorConflictRetriesExhausted = -6000, + AWSCognitoErrorWiFiNotAvailable = -7000, + AWSCognitoErrorDeviceNotRegistered = -8000, + AWSCognitoErrorSyncAlreadyPending = -9000, + AWSCognitoErrorTimedOutWaitingForInFlightSync = -10000, +}; + +@property (nonatomic, strong, readonly) AWSServiceConfiguration *configuration; + +/** + A conflict resolution handler that will receive calls when there is a + conflict during a sync operation. A conflict will occur when both remote and + local data have been updated since the last sync time. + When not explicitly set, we will use the default conflict resolution of + 'last writer wins', where the data most recently updated will be persisted. + This handler will be propagated to any AWSCognitoDataset opened by this client. + */ +@property (nonatomic, strong) AWSCognitoRecordConflictHandler conflictHandler; + +/** + A deleted dataset handler. This handler will be called during a synchronization + when the remote service indicates that a dataset has been deleted. + Returning YES from the handler will cause the service to recreate the dataset + on the remote on the next synchronization. Returning NO or leaving this property + nil will cause the client to delete the dataset locally. + This handler will be propagated to any AWSCognitoDataset opened by this client. + */ +@property (nonatomic, strong) AWSCognitoDatasetDeletedHandler datasetDeletedHandler; + +/** + A merged dataset handler. This handler will be called during a synchronization + when the remote service indicates that other datasets should be merged with this one. + Merged datasets should be fetched, their data overlayed locally and then removed. + Failing to implement this handler will result in merged datasets remaining on the + service indefinitely. + This handler will be propagated to any AWSCognitoDataset opened by this client. + */ +@property (nonatomic, strong) AWSCognitoDatasetMergedHandler datasetMergedHandler; + +/** + The identifier used for this client in Amazon Cognito. If not supplied + Amazon Cognito will create a random GUID for the device. + */ +@property (nonatomic, strong) NSString *deviceId; + +/** + The number of times to attempt a synchronization before failing. This will + be set on any AWSCognitoDatasets opened with this client. Defaults to 5 if not set. + */ +@property (nonatomic, assign) uint32_t synchronizeRetries; + +/** + Only synchronize if device is on a WiFi network. Defaults to NO if not set. + */ +@property (nonatomic, assign) BOOL synchronizeOnWiFiOnly; + +/** + Returns the singleton service client. If the singleton object does not exist, the SDK instantiates the default service client with `defaultServiceConfiguration` from `[AWSServiceManager defaultServiceManager]`. The reference to this object is maintained by the SDK, and you do not need to retain it manually. Returns `nil` if the credentials provider is not an instance of `AWSCognitoCredentials` provider. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialProvider) + AWSServiceManager.default().defaultServiceConfiguration = configuration + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 + credentialsProvider:credentialsProvider]; + [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration; + + return YES; + } + + Then call the following to get the default service client: + + *Swift* + + let Cognito = AWSCognito.default() + + *Objective-C* + + AWSCognito *Cognito = [AWSCognito defaultCognito]; + + @return The default service client. + */ ++ (instancetype)defaultCognito; + +/** + Creates a service client with the given service configuration and registers it for the key. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognito.register(with: configuration!, forKey: "USWest2Cognito") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognito registerCognitoWithConfiguration:configuration forKey:@"USWest2Cognito"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let Cognito = AWSCognito(forKey: "USWest2Cognito") + + *Objective-C* + + AWSCognito *Cognito = [AWSCognito CognitoForKey:@"USWest2Cognito"]; + + @warning After calling this method, do not modify the configuration object. It may cause unspecified behaviors. + + @param configuration A service configuration object. + @param key A string to identify the service client. + */ ++ (void)registerCognitoWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key; + +/** + Retrieves the service client associated with the key. You need to call `+ registerCognitoWithConfiguration:forKey:` before invoking this method. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognito.register(with: configuration!, forKey: "USWest2Cognito") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognito registerCognitoWithConfiguration:configuration forKey:@"USWest2Cognito"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let Cognito = AWSCognito(forKey: "USWest2Cognito") + + *Objective-C* + + AWSCognito *Cognito = [AWSCognito CognitoForKey:@"USWest2Cognito"]; + + @param key A string to identify the service client. + + @return An instance of the service client. + */ ++ (instancetype)CognitoForKey:(NSString *)key; + +/** + Removes the service client associated with the key and release it. + + @warning Before calling this method, make sure no method is running on this client. + + @param key A string to identify the service client. + */ ++ (void)removeCognitoForKey:(NSString *)key; + +/** + Opens an existing dataset or creates a new one. + + @return handle to AWSCognitoDataset + */ +- (AWSCognitoDataset *)openOrCreateDataset:(NSString *)datasetName; + +/** + List all datasets our client is aware of. Call refreshDatasetMetadata to ensure + the client has knowledge of all datasets available on the remote store. + + @return NSArray of AWSCognitoDatasetMetadata + */ +- (NSArray *)listDatasets; + +/** + List all of the datasets. Returns a AWSTask. The result of this task will be an array of + AWSCognitoDatasetMetadata objects. + */ +- (AWSTask *> *)refreshDatasetMetadata; + +/** + Wipe all cached data. + */ +- (void)wipe; + +/** + Get the default, last writer wins conflict handler + */ ++ (AWSCognitoRecordConflictHandler) defaultConflictHandler; + +/** + Register this device for push notifications. You will not receive any notifications until you actually subscribe the + dataset you want to receive push notifications for. If your build targets Release, this will register the device + with APNS, if your build targets Debug this will register the device with APNS_SANDBOX. Returns a AWSTask. + The result of this task will be a AWSCognitoSyncRegisterDeviceResponse. + */ +- (AWSTask *)registerDevice: (NSData *) deviceToken; + +/** + Get the device id Cognito Sync gave this device. nil if device has never been registered + */ ++ (NSString *) cognitoDeviceId; + +/** + Used to override the platform for push notifications. If you are not using the CocoaPods distribution, + #ifdef DEBUG + [[AWSCognito defaultCognito] setPushPlatform:AWSCognitoSyncPlatformApnsSandbox]; + #endif + will set push notifications to use the APNS_SANDBOX if your build targets Debug. Otherwise it will + always use APNS. + */ + ++ (void)setPushPlatform:(AWSCognitoSyncPlatform) pushPlatform; + +/** + The push platform for push notifications + */ ++ (AWSCognitoSyncPlatform)pushPlatform; + +/** + Subscribe to a list of datasets. Make sure you have called synchronize on each of the datasets in the list + at least once prior to calling this. Returns a AWSTask. The result of this task will be a NSArray of + AWSCognitoSyncSubscribeToDatasetResponse + */ +- (AWSTask *)subscribe:(NSArray *) datasetNames; + +/** + Subscribe to all datasets you have locally. Make sure you have called synchronize on all of your local datasets + at least once prior to calling this. Returns a AWSTask. The result of this task will be a NSArray of + AWSCognitoSyncSubscribeToDatasetResponse + */ +- (AWSTask *)subscribeAll; + +/** + Unsubscribe to a list of datasets. Returns a AWSTask. The result of this task will be a NSArray of + AWSCognitoSyncUnsubscribeToDatasetResponse + */ +- (AWSTask *)unsubscribe:(NSArray *) datasetNames; + +/** + Unsubscribe to all datasets you have locally. Make sure you have called synchronize on all of your local datasets + at least once prior to calling this. Returns a AWSTask. The result of this task will be a NSArray of + AWSCognitoSyncUnsubscribeToDatasetResponse + */ +- (AWSTask *)unsubscribeAll; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.m b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.m new file mode 100644 index 00000000..0a6a53a5 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/AWSCognitoService.m @@ -0,0 +1,401 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoService.h" +#import +#import "AWSCognitoRecord_Internal.h" +#import "AWSCognitoSQLiteManager.h" +#import "AWSCognitoDataset.h" +#import "AWSCognitoConstants.h" +#import "AWSCognitoUtil.h" +#import "AWSCognitoDataset_Internal.h" +#import +#import "AWSCognitoHandlers.h" +#import "AWSCognitoConflict_Internal.h" +#import +#import +#import + +#import "FABKitProtocol.h" +#import "Fabric+FABKits.h" + +static NSString *const AWSInfoCognito = @"Cognito"; +static NSString *const AWSCognitoSDKVersion = @"2.5.6"; + +NSString *const AWSCognitoDidStartSynchronizeNotification = @"com.amazon.cognito.AWSCognitoDidStartSynchronizeNotification"; +NSString *const AWSCognitoDidEndSynchronizeNotification = @"com.amazon.cognito.AWSCognitoDidEndSynchronizeNotification"; +NSString *const AWSCognitoDidChangeLocalValueFromRemoteNotification = @"com.amazon.cognito.AWSCognitoDidChangeLocalValueFromRemoteNotification"; +NSString *const AWSCognitoDidChangeRemoteValueNotification = @"com.amazon.cognito.AWSCognitoDidChangeRemoteValueNotification"; +NSString *const AWSCognitoDidFailToSynchronizeNotification = @"com.amazon.cognito.AWSCognitoDidFailToSynchronizeNotification"; +NSString *const AWSCognitoUnknownDataTypeNotification = @"com.amazon.cognito.AWSCognitoUnknownDataTypeNotification"; + +// For the cognito client to communicate to open datasets +NSString *const AWSCognitoIdentityIdChangedInternalNotification = @"com.amazonaws.services.cognitoidentity.AWSCognitoIdentityIdChangedInternalNotification"; + +NSString *const AWSCognitoErrorDomain = @"com.amazon.cognito.AWSCognitoErrorDomain"; + +static AWSUICKeyChainStore *keychain = nil; + +static AWSCognitoSyncPlatform _pushPlatform; + +@interface AWSCognito() + +@property (nonatomic, strong) AWSCognitoSQLiteManager *sqliteManager; +@property (nonatomic, strong) AWSCognitoSync *cognitoService; +@property (nonatomic, strong) AWSCognitoCredentialsProvider *cognitoCredentialsProvider; +@property (nonatomic, strong) AWSUICKeyChainStore *keychain; + +@end + +@interface AWSCognitoIdentity() + ++ (void)internalInitializeIfNeeded; + +@end + +@interface AWSCognitoSync() + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration; + +@end + +@implementation AWSCognito + +static AWSSynchronizedMutableDictionary *_serviceClients = nil; + +#pragma mark - Fabric + ++ (NSString *)bundleIdentifier { + return @"com.amazonaws.sdk.ios.AWSCognito"; +} + ++ (NSString *)kitDisplayVersion { + return AWSiOSSDKVersion; +} + ++ (void)initializeIfNeeded { + [AWSCognitoIdentity internalInitializeIfNeeded]; +} + +#pragma mark - Setups + ++ (void)initialize { + [super initialize]; + + if (![AWSiOSSDKVersion isEqualToString:AWSCognitoSDKVersion]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"AWSCore and AWSCognito versions need to match. Check your SDK installation. AWSCore: %@ AWSCognito: %@", AWSiOSSDKVersion, AWSCognitoSDKVersion] + userInfo:nil]; + } + + keychain = [AWSUICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@", [NSBundle mainBundle].bundleIdentifier, [AWSCognito class]]]; + _pushPlatform = [AWSCognitoUtil pushPlatform]; +} + ++ (instancetype)defaultCognito { + static AWSCognito *_defaultCognito = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AWSServiceConfiguration *serviceConfiguration = nil; + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoCognito]; + if (serviceInfo) { + serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + } + + if (!serviceConfiguration) { + serviceConfiguration = [AWSServiceManager defaultServiceManager].defaultServiceConfiguration; + } + + if (!serviceConfiguration) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method." + userInfo:nil]; + } + + if (![serviceConfiguration.credentialsProvider isKindOfClass:[AWSCognitoCredentialsProvider class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"`AWSCognito` needs `AWSCognitoCredentialsProvider` to be set as a credentials provider." + userInfo:nil]; + } + _defaultCognito = [[AWSCognito alloc] initWithConfiguration:serviceConfiguration]; + }); + + return _defaultCognito; +} + ++ (void)registerCognitoWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _serviceClients = [AWSSynchronizedMutableDictionary new]; + }); + [_serviceClients setObject:[[AWSCognito alloc] initWithConfiguration:configuration] + forKey:key]; +} + ++ (instancetype)CognitoForKey:(NSString *)key { + @synchronized(self) { + AWSCognito *serviceClient = [_serviceClients objectForKey:key]; + if (serviceClient) { + return serviceClient; + } + + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoCognito + forKey:key]; + if (serviceInfo) { + AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + [AWSCognito registerCognitoWithConfiguration:serviceConfiguration + forKey:key]; + } + + return [_serviceClients objectForKey:key]; + } +} + ++ (void)removeCognitoForKey:(NSString *)key { + [_serviceClients removeObjectForKey:key]; +} + +- (instancetype)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"`- init` is not a valid initializer. Use `+ defaultCognito` or `+ CognitoForKey:` instead." + userInfo:nil]; + return nil; +} + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration +{ + // Cognito needs an AWSCognitoCredentialsProvider + if (![configuration.credentialsProvider isKindOfClass:[AWSCognitoCredentialsProvider class]]) { + return nil; + } + + if (self = [super init]) { + _configuration = [configuration copy]; + _cognitoCredentialsProvider = _configuration.credentialsProvider; + + // set other default values + NSString * serviceDeviceId = [AWSCognito cognitoDeviceId]; + _deviceId = (serviceDeviceId) == nil ? @"LOCAL" : serviceDeviceId; + _synchronizeRetries = AWSCognitoMaxSyncRetries; + _synchronizeOnWiFiOnly = AWSCognitoSynchronizeOnWiFiOnly; + + _conflictHandler = [AWSCognito defaultConflictHandler]; + _sqliteManager = [[AWSCognitoSQLiteManager alloc] initWithIdentityId:_cognitoCredentialsProvider.identityId deviceId:_deviceId]; + _cognitoService = [[AWSCognitoSync alloc] initWithConfiguration:configuration]; + // register to know when the identity on our provider changes + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(identityChanged:) name:AWSCognitoIdentityIdChangedNotification object:_cognitoCredentialsProvider.identityProvider]; + + + } + + return self; +} + +-(void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (AWSCognitoDataset *)openOrCreateDataset:(NSString * ) datasetName{ + AWSCognitoDataset *dataset = [[AWSCognitoDataset alloc] initWithDatasetName:datasetName + sqliteManager:self.sqliteManager + cognitoService:self.cognitoService]; + dataset.conflictHandler = self.conflictHandler; + dataset.datasetDeletedHandler = self.datasetDeletedHandler; + dataset.datasetMergedHandler = self.datasetMergedHandler; + dataset.synchronizeRetries = self.synchronizeRetries; + dataset.synchronizeOnWiFiOnly = self.synchronizeOnWiFiOnly; + + // register the dataset to receive notifications from this instance when the identity changes + [[NSNotificationCenter defaultCenter] addObserver:dataset selector:@selector(identityChanged:) name:AWSCognitoIdentityIdChangedInternalNotification object:self]; + + return dataset; +} + +- (void)wipe { + [self.sqliteManager deleteAllData]; + [self.cognitoCredentialsProvider clearKeychain]; +} + +- (AWSTask *> *)refreshDatasetMetadata { + return [[[self.cognitoCredentialsProvider getIdentityId] continueWithBlock:^id(AWSTask *task) { + if (task.error) { + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoAuthenticationFailed userInfo:nil]]; + } + AWSCognitoSyncListDatasetsRequest *request = [AWSCognitoSyncListDatasetsRequest new]; + request.identityPoolId = self.cognitoCredentialsProvider.identityPoolId; + request.identityId = self.cognitoCredentialsProvider.identityId; + return [self.cognitoService listDatasets:request]; + }] continueWithBlock:^id(AWSTask *task) { + if(task.isCancelled){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]]; + }else if(task.error){ + AWSDDLogError(@"Unable to list datasets: %@", task.error); + return task; + }else { + AWSCognitoSyncListDatasetsResponse* response = task.result; + [self.sqliteManager putDatasetMetadata: response.datasets error:nil]; + return [AWSTask taskWithResult:response.datasets]; + } + }]; +} + +- (NSArray *)listDatasets { + return [self.sqliteManager getDatasets:nil]; +} + +- (void) setDeviceId:(NSString *)deviceId { + self.sqliteManager.deviceId = deviceId; + _deviceId = deviceId; +} + +- (void)identityChanged:(NSNotification *)notification { + AWSDDLogDebug(@"IdentityChanged"); + NSDictionary *userInfo = notification.userInfo; + + NSString *oldId = [userInfo objectForKey:AWSCognitoNotificationPreviousId]; + NSString *newId = [userInfo objectForKey:AWSCognitoNotificationNewId]; + + NSError *error; + + if ([self.sqliteManager reparentDatasets:oldId withNewId:newId error:&error]) { + // update the id for the sqlitemanager + self.sqliteManager.identityId = newId; + + // Now that we've udpated the data, notify open datasets + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoIdentityIdChangedInternalNotification + object:self + userInfo:userInfo]; + }); + } + else { + // TODO: How do we surface this error? + } +} + ++(NSString *) cognitoDeviceId { + return keychain[[AWSCognitoUtil deviceIdKey:_pushPlatform]]; +} + ++(NSString *) cognitoDeviceIdentity { + return keychain[[AWSCognitoUtil deviceIdentityKey:_pushPlatform]]; +} + +-(AWSTask *)registerDevice:(NSData *) deviceToken { + const unsigned char* bytes = (const unsigned char*)[deviceToken bytes]; + NSMutableString * devTokenHex = [[NSMutableString alloc] initWithCapacity:2*deviceToken.length]; + for(int i=0; i * _Nonnull task) { + AWSCognitoSyncRegisterDeviceResponse* response = task.result; + keychain[[AWSCognitoUtil deviceIdKey:_pushPlatform]] = response.deviceId; + keychain[[AWSCognitoUtil deviceIdentityKey:_pushPlatform]] = self.cognitoCredentialsProvider.identityId; + [self setDeviceId:response.deviceId]; + return [AWSTask taskWithResult:response.deviceId]; + }]; + }] continueWithBlock:^id(AWSTask *task) { + if(task.isCancelled){ + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoErrorTaskCanceled userInfo:nil]]; + } + + if(task.error){ + AWSDDLogError(@"Unable to register device: %@", task.error); + } + + return task; + }]; +} + ++(void)setPushPlatform:(AWSCognitoSyncPlatform) pushPlatform { + _pushPlatform = pushPlatform; +} + ++(AWSCognitoSyncPlatform)pushPlatform { + return _pushPlatform; +} + +-(AWSTask *)subscribe:(NSArray *) datasetNames { + NSMutableArray *tasks = [NSMutableArray new]; + for (NSString * datasetName in datasetNames) { + [tasks addObject:[[self openOrCreateDataset:datasetName] subscribe]]; + } + return [AWSTask taskForCompletionOfAllTasks:tasks]; +} + +-(AWSTask *)subscribeAll { + NSArray * datasets = [self listDatasets]; + NSMutableArray * datasetNames = [NSMutableArray new]; + for (AWSCognitoDatasetMetadata * dataset in datasets) { + [datasetNames addObject: dataset.name]; + } + return [self subscribe:datasetNames]; +} + +-(AWSTask *)unsubscribe:(NSArray *) datasetNames { + NSMutableArray *tasks = [NSMutableArray new]; + for (NSString * datasetName in datasetNames) { + [tasks addObject:[[self openOrCreateDataset:datasetName] unsubscribe]]; + } + return [AWSTask taskForCompletionOfAllTasks:tasks]; +} + +-(AWSTask *)unsubscribeAll { + NSArray * datasets = [self listDatasets]; + NSMutableArray * datasetNames = [NSMutableArray new]; + for (AWSCognitoDatasetMetadata * dataset in datasets) { + [datasetNames addObject:dataset.name]; + } + return [self unsubscribe:datasetNames]; +} + ++ (AWSCognitoRecordConflictHandler) defaultConflictHandler { + return ^AWSCognitoResolvedConflict* (NSString *datasetName, AWSCognitoConflict *conflict) { + AWSDDLogDebug(@"Last writer wins conflict resolution for dataset %@", datasetName); + if (conflict.remoteRecord == nil || [conflict.localRecord.lastModified compare:conflict.remoteRecord.lastModified] == NSOrderedDescending) + { + return [[AWSCognitoResolvedConflict alloc] initWithLocalRecord: conflict]; + } + else + { + return [[AWSCognitoResolvedConflict alloc] initWithRemoteRecord: conflict]; + } + }; +} + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.h b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.h new file mode 100644 index 00000000..05e2c52e --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.h @@ -0,0 +1,1032 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const AWSCognitoSyncErrorDomain; + +typedef NS_ENUM(NSInteger, AWSCognitoSyncErrorType) { + AWSCognitoSyncErrorUnknown, + AWSCognitoSyncErrorAlreadyStreamed, + AWSCognitoSyncErrorConcurrentModification, + AWSCognitoSyncErrorDuplicateRequest, + AWSCognitoSyncErrorInternalError, + AWSCognitoSyncErrorInvalidConfiguration, + AWSCognitoSyncErrorInvalidLambdaFunctionOutput, + AWSCognitoSyncErrorInvalidParameter, + AWSCognitoSyncErrorLambdaThrottled, + AWSCognitoSyncErrorLimitExceeded, + AWSCognitoSyncErrorNotAuthorized, + AWSCognitoSyncErrorResourceConflict, + AWSCognitoSyncErrorResourceNotFound, + AWSCognitoSyncErrorTooManyRequests, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoSyncBulkPublishStatus) { + AWSCognitoSyncBulkPublishStatusUnknown, + AWSCognitoSyncBulkPublishStatusNotStarted, + AWSCognitoSyncBulkPublishStatusInProgress, + AWSCognitoSyncBulkPublishStatusFailed, + AWSCognitoSyncBulkPublishStatusSucceeded, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoSyncOperation) { + AWSCognitoSyncOperationUnknown, + AWSCognitoSyncOperationReplace, + AWSCognitoSyncOperationRemove, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoSyncPlatform) { + AWSCognitoSyncPlatformUnknown, + AWSCognitoSyncPlatformApns, + AWSCognitoSyncPlatformApnsSandbox, + AWSCognitoSyncPlatformGcm, + AWSCognitoSyncPlatformAdm, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoSyncStreamingStatus) { + AWSCognitoSyncStreamingStatusUnknown, + AWSCognitoSyncStreamingStatusEnabled, + AWSCognitoSyncStreamingStatusDisabled, +}; + +@class AWSCognitoSyncBulkPublishRequest; +@class AWSCognitoSyncBulkPublishResponse; +@class AWSCognitoSyncCognitoStreams; +@class AWSCognitoSyncDataset; +@class AWSCognitoSyncDeleteDatasetRequest; +@class AWSCognitoSyncDeleteDatasetResponse; +@class AWSCognitoSyncDescribeDatasetRequest; +@class AWSCognitoSyncDescribeDatasetResponse; +@class AWSCognitoSyncDescribeIdentityPoolUsageRequest; +@class AWSCognitoSyncDescribeIdentityPoolUsageResponse; +@class AWSCognitoSyncDescribeIdentityUsageRequest; +@class AWSCognitoSyncDescribeIdentityUsageResponse; +@class AWSCognitoSyncGetBulkPublishDetailsRequest; +@class AWSCognitoSyncGetBulkPublishDetailsResponse; +@class AWSCognitoSyncGetCognitoEventsRequest; +@class AWSCognitoSyncGetCognitoEventsResponse; +@class AWSCognitoSyncGetIdentityPoolConfigurationRequest; +@class AWSCognitoSyncGetIdentityPoolConfigurationResponse; +@class AWSCognitoSyncIdentityPoolUsage; +@class AWSCognitoSyncIdentityUsage; +@class AWSCognitoSyncListDatasetsRequest; +@class AWSCognitoSyncListDatasetsResponse; +@class AWSCognitoSyncListIdentityPoolUsageRequest; +@class AWSCognitoSyncListIdentityPoolUsageResponse; +@class AWSCognitoSyncListRecordsRequest; +@class AWSCognitoSyncListRecordsResponse; +@class AWSCognitoSyncPushSync; +@class AWSCognitoSyncRecord; +@class AWSCognitoSyncRecordPatch; +@class AWSCognitoSyncRegisterDeviceRequest; +@class AWSCognitoSyncRegisterDeviceResponse; +@class AWSCognitoSyncSetCognitoEventsRequest; +@class AWSCognitoSyncSetIdentityPoolConfigurationRequest; +@class AWSCognitoSyncSetIdentityPoolConfigurationResponse; +@class AWSCognitoSyncSubscribeToDatasetRequest; +@class AWSCognitoSyncSubscribeToDatasetResponse; +@class AWSCognitoSyncUnsubscribeFromDatasetRequest; +@class AWSCognitoSyncUnsubscribeFromDatasetResponse; +@class AWSCognitoSyncUpdateRecordsRequest; +@class AWSCognitoSyncUpdateRecordsResponse; + +/** + The input for the BulkPublish operation. + Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncBulkPublishRequest : AWSRequest + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + The output for the BulkPublish operation. + */ +@interface AWSCognitoSyncBulkPublishResponse : AWSModel + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + Configuration options for configure Cognito streams. + */ +@interface AWSCognitoSyncCognitoStreams : AWSModel + + +/** + The ARN of the role Amazon Cognito can assume in order to publish to the stream. This role must grant access to Amazon Cognito (cognito-sync) to invoke PutRecord on your Cognito stream. + */ +@property (nonatomic, strong) NSString * _Nullable roleArn; + +/** + The name of the Cognito stream to receive updates. This stream must be in the developers account and in the same region as the identity pool. + */ +@property (nonatomic, strong) NSString * _Nullable streamName; + +/** + Status of the Cognito streams. Valid values are:

ENABLED - Streaming of updates to identity pool is enabled.

DISABLED - Streaming of updates to identity pool is disabled. Bulk publish will also fail if StreamingStatus is DISABLED.

+ */ +@property (nonatomic, assign) AWSCognitoSyncStreamingStatus streamingStatus; + +@end + +/** + A collection of data for an identity pool. An identity pool can have multiple datasets. A dataset is per identity and can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs. + */ +@interface AWSCognitoSyncDataset : AWSModel + + +/** + Date on which the dataset was created. + */ +@property (nonatomic, strong) NSDate * _Nullable creationDate; + +/** + Total size in bytes of the records in this dataset. + */ +@property (nonatomic, strong) NSNumber * _Nullable dataStorage; + +/** + A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot). + */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + The device that made the last change to this dataset. + */ +@property (nonatomic, strong) NSString * _Nullable lastModifiedBy; + +/** + Date when the dataset was last modified. + */ +@property (nonatomic, strong) NSDate * _Nullable lastModifiedDate; + +/** + Number of records in this dataset. + */ +@property (nonatomic, strong) NSNumber * _Nullable numRecords; + +@end + +/** + A request to delete the specific dataset. + Required parameters: [IdentityPoolId, IdentityId, DatasetName] + */ +@interface AWSCognitoSyncDeleteDatasetRequest : AWSRequest + + +/** + A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot). + */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + Response to a successful DeleteDataset request. + */ +@interface AWSCognitoSyncDeleteDatasetResponse : AWSModel + + +/** + A collection of data for an identity pool. An identity pool can have multiple datasets. A dataset is per identity and can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs. + */ +@property (nonatomic, strong) AWSCognitoSyncDataset * _Nullable dataset; + +@end + +/** + A request for meta data about a dataset (creation date, number of records, size) by owner and dataset name. + Required parameters: [IdentityPoolId, IdentityId, DatasetName] + */ +@interface AWSCognitoSyncDescribeDatasetRequest : AWSRequest + + +/** + A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot). + */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + Response to a successful DescribeDataset request. + */ +@interface AWSCognitoSyncDescribeDatasetResponse : AWSModel + + +/** + Meta data for a collection of data for an identity. An identity can have multiple datasets. A dataset can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs. + */ +@property (nonatomic, strong) AWSCognitoSyncDataset * _Nullable dataset; + +@end + +/** + A request for usage information about the identity pool. + Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncDescribeIdentityPoolUsageRequest : AWSRequest + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + Response to a successful DescribeIdentityPoolUsage request. + */ +@interface AWSCognitoSyncDescribeIdentityPoolUsageResponse : AWSModel + + +/** + Information about the usage of the identity pool. + */ +@property (nonatomic, strong) AWSCognitoSyncIdentityPoolUsage * _Nullable identityPoolUsage; + +@end + +/** + A request for information about the usage of an identity pool. + Required parameters: [IdentityPoolId, IdentityId] + */ +@interface AWSCognitoSyncDescribeIdentityUsageRequest : AWSRequest + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + The response to a successful DescribeIdentityUsage request. + */ +@interface AWSCognitoSyncDescribeIdentityUsageResponse : AWSModel + + +/** + Usage information for the identity. + */ +@property (nonatomic, strong) AWSCognitoSyncIdentityUsage * _Nullable identityUsage; + +@end + +/** + The input for the GetBulkPublishDetails operation. + Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncGetBulkPublishDetailsRequest : AWSRequest + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + The output for the GetBulkPublishDetails operation. + */ +@interface AWSCognitoSyncGetBulkPublishDetailsResponse : AWSModel + + +/** + If BulkPublishStatus is SUCCEEDED, the time the last bulk publish operation completed. + */ +@property (nonatomic, strong) NSDate * _Nullable bulkPublishCompleteTime; + +/** + The date/time at which the last bulk publish was initiated. + */ +@property (nonatomic, strong) NSDate * _Nullable bulkPublishStartTime; + +/** + Status of the last bulk publish operation, valid values are:

NOT_STARTED - No bulk publish has been requested for this identity pool

IN_PROGRESS - Data is being published to the configured stream

SUCCEEDED - All data for the identity pool has been published to the configured stream

FAILED - Some portion of the data has failed to publish, check FailureMessage for the cause.

+ */ +@property (nonatomic, assign) AWSCognitoSyncBulkPublishStatus bulkPublishStatus; + +/** + If BulkPublishStatus is FAILED this field will contain the error message that caused the bulk publish to fail. + */ +@property (nonatomic, strong) NSString * _Nullable failureMessage; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

A request for a list of the configured Cognito Events

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncGetCognitoEventsRequest : AWSRequest + + +/** +

The Cognito Identity Pool ID for the request

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

The response from the GetCognitoEvents request

+ */ +@interface AWSCognitoSyncGetCognitoEventsResponse : AWSModel + + +/** +

The Cognito Events returned from the GetCognitoEvents request

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable events; + +@end + +/** +

The input for the GetIdentityPoolConfiguration operation.

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncGetIdentityPoolConfigurationRequest : AWSRequest + + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. This is the ID of the pool for which to return a configuration.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

The output for the GetIdentityPoolConfiguration operation.

+ */ +@interface AWSCognitoSyncGetIdentityPoolConfigurationResponse : AWSModel + + +/** + Options to apply to this identity pool for Amazon Cognito streams. + */ +@property (nonatomic, strong) AWSCognitoSyncCognitoStreams * _Nullable cognitoStreams; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

Options to apply to this identity pool for push synchronization.

+ */ +@property (nonatomic, strong) AWSCognitoSyncPushSync * _Nullable pushSync; + +@end + +/** + Usage information for the identity pool. + */ +@interface AWSCognitoSyncIdentityPoolUsage : AWSModel + + +/** + Data storage information for the identity pool. + */ +@property (nonatomic, strong) NSNumber * _Nullable dataStorage; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + Date on which the identity pool was last modified. + */ +@property (nonatomic, strong) NSDate * _Nullable lastModifiedDate; + +/** + Number of sync sessions for the identity pool. + */ +@property (nonatomic, strong) NSNumber * _Nullable syncSessionsCount; + +@end + +/** + Usage information for the identity. + */ +@interface AWSCognitoSyncIdentityUsage : AWSModel + + +/** + Total data storage for this identity. + */ +@property (nonatomic, strong) NSNumber * _Nullable dataStorage; + +/** + Number of datasets for the identity. + */ +@property (nonatomic, strong) NSNumber * _Nullable datasetCount; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + Date on which the identity was last modified. + */ +@property (nonatomic, strong) NSDate * _Nullable lastModifiedDate; + +@end + +/** + Request for a list of datasets for an identity. + Required parameters: [IdentityId, IdentityPoolId] + */ +@interface AWSCognitoSyncListDatasetsRequest : AWSRequest + + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + The maximum number of results to be returned. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + Returned for a successful ListDatasets request. + */ +@interface AWSCognitoSyncListDatasetsResponse : AWSModel + + +/** + Number of datasets returned. + */ +@property (nonatomic, strong) NSNumber * _Nullable count; + +/** + A set of datasets. + */ +@property (nonatomic, strong) NSArray * _Nullable datasets; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + A request for usage information on an identity pool. + */ +@interface AWSCognitoSyncListIdentityPoolUsageRequest : AWSRequest + + +/** + The maximum number of results to be returned. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + Returned for a successful ListIdentityPoolUsage request. + */ +@interface AWSCognitoSyncListIdentityPoolUsageResponse : AWSModel + + +/** + Total number of identities for the identity pool. + */ +@property (nonatomic, strong) NSNumber * _Nullable count; + +/** + Usage information for the identity pools. + */ +@property (nonatomic, strong) NSArray * _Nullable identityPoolUsages; + +/** + The maximum number of results to be returned. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + A request for a list of records. + Required parameters: [IdentityPoolId, IdentityId, DatasetName] + */ +@interface AWSCognitoSyncListRecordsRequest : AWSRequest + + +/** + A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot). + */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + The last server sync count for this record. + */ +@property (nonatomic, strong) NSNumber * _Nullable lastSyncCount; + +/** + The maximum number of results to be returned. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +/** + A token containing a session ID, identity ID, and expiration. + */ +@property (nonatomic, strong) NSString * _Nullable syncSessionToken; + +@end + +/** + Returned for a successful ListRecordsRequest. + */ +@interface AWSCognitoSyncListRecordsResponse : AWSModel + + +/** + Total number of records. + */ +@property (nonatomic, strong) NSNumber * _Nullable count; + +/** + A boolean value specifying whether to delete the dataset locally. + */ +@property (nonatomic, strong) NSNumber * _Nullable datasetDeletedAfterRequestedSyncCount; + +/** + Indicates whether the dataset exists. + */ +@property (nonatomic, strong) NSNumber * _Nullable datasetExists; + +/** + Server sync count for this dataset. + */ +@property (nonatomic, strong) NSNumber * _Nullable datasetSyncCount; + +/** + The user/device that made the last change to this record. + */ +@property (nonatomic, strong) NSString * _Nullable lastModifiedBy; + +/** + Names of merged datasets. + */ +@property (nonatomic, strong) NSArray * _Nullable mergedDatasetNames; + +/** + A pagination token for obtaining the next page of results. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +/** + A list of all records. + */ +@property (nonatomic, strong) NSArray * _Nullable records; + +/** + A token containing a session ID, identity ID, and expiration. + */ +@property (nonatomic, strong) NSString * _Nullable syncSessionToken; + +@end + +/** +

Configuration options to be applied to the identity pool.

+ */ +@interface AWSCognitoSyncPushSync : AWSModel + + +/** +

List of SNS platform application ARNs that could be used by clients.

+ */ +@property (nonatomic, strong) NSArray * _Nullable applicationArns; + +/** +

A role configured to allow Cognito to call SNS on behalf of the developer.

+ */ +@property (nonatomic, strong) NSString * _Nullable roleArn; + +@end + +/** + The basic data structure of a dataset. + */ +@interface AWSCognitoSyncRecord : AWSModel + + +/** + The last modified date of the client device. + */ +@property (nonatomic, strong) NSDate * _Nullable deviceLastModifiedDate; + +/** + The key for the record. + */ +@property (nonatomic, strong) NSString * _Nullable key; + +/** + The user/device that made the last change to this record. + */ +@property (nonatomic, strong) NSString * _Nullable lastModifiedBy; + +/** + The date on which the record was last modified. + */ +@property (nonatomic, strong) NSDate * _Nullable lastModifiedDate; + +/** + The server sync count for this record. + */ +@property (nonatomic, strong) NSNumber * _Nullable syncCount; + +/** + The value for the record. + */ +@property (nonatomic, strong) NSString * _Nullable value; + +@end + +/** + An update operation for a record. + Required parameters: [Op, Key, SyncCount] + */ +@interface AWSCognitoSyncRecordPatch : AWSModel + + +/** + The last modified date of the client device. + */ +@property (nonatomic, strong) NSDate * _Nullable deviceLastModifiedDate; + +/** + The key associated with the record patch. + */ +@property (nonatomic, strong) NSString * _Nullable key; + +/** + An operation, either replace or remove. + */ +@property (nonatomic, assign) AWSCognitoSyncOperation op; + +/** + Last known server sync count for this record. Set to 0 if unknown. + */ +@property (nonatomic, strong) NSNumber * _Nullable syncCount; + +/** + The value associated with the record patch. + */ +@property (nonatomic, strong) NSString * _Nullable value; + +@end + +/** +

A request to RegisterDevice.

+ Required parameters: [IdentityPoolId, IdentityId, Platform, Token] + */ +@interface AWSCognitoSyncRegisterDeviceRequest : AWSRequest + + +/** +

The unique ID for this identity.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. Here, the ID of the pool that the identity belongs to.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

The SNS platform type (e.g. GCM, SDM, APNS, APNS_SANDBOX).

+ */ +@property (nonatomic, assign) AWSCognitoSyncPlatform platform; + +/** +

The push token.

+ */ +@property (nonatomic, strong) NSString * _Nullable token; + +@end + +/** +

Response to a RegisterDevice request.

+ */ +@interface AWSCognitoSyncRegisterDeviceResponse : AWSModel + + +/** +

The unique ID generated for this device by Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable deviceId; + +@end + +/** +

A request to configure Cognito Events"

" + Required parameters: [IdentityPoolId, Events] + */ +@interface AWSCognitoSyncSetCognitoEventsRequest : AWSRequest + + +/** +

The events to configure

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable events; + +/** +

The Cognito Identity Pool to use when configuring Cognito Events

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

The input for the SetIdentityPoolConfiguration operation.

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoSyncSetIdentityPoolConfigurationRequest : AWSRequest + + +/** + Options to apply to this identity pool for Amazon Cognito streams. + */ +@property (nonatomic, strong) AWSCognitoSyncCognitoStreams * _Nullable cognitoStreams; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. This is the ID of the pool to modify.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

Options to apply to this identity pool for push synchronization.

+ */ +@property (nonatomic, strong) AWSCognitoSyncPushSync * _Nullable pushSync; + +@end + +/** +

The output for the SetIdentityPoolConfiguration operation

+ */ +@interface AWSCognitoSyncSetIdentityPoolConfigurationResponse : AWSModel + + +/** + Options to apply to this identity pool for Amazon Cognito streams. + */ +@property (nonatomic, strong) AWSCognitoSyncCognitoStreams * _Nullable cognitoStreams; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

Options to apply to this identity pool for push synchronization.

+ */ +@property (nonatomic, strong) AWSCognitoSyncPushSync * _Nullable pushSync; + +@end + +/** +

A request to SubscribeToDatasetRequest.

+ Required parameters: [IdentityPoolId, IdentityId, DatasetName, DeviceId] + */ +@interface AWSCognitoSyncSubscribeToDatasetRequest : AWSRequest + + +/** +

The name of the dataset to subcribe to.

+ */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** +

The unique ID generated for this device by Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable deviceId; + +/** +

Unique ID for this identity.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. The ID of the pool to which the identity belongs.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

Response to a SubscribeToDataset request.

+ */ +@interface AWSCognitoSyncSubscribeToDatasetResponse : AWSModel + + +@end + +/** +

A request to UnsubscribeFromDataset.

+ Required parameters: [IdentityPoolId, IdentityId, DatasetName, DeviceId] + */ +@interface AWSCognitoSyncUnsubscribeFromDatasetRequest : AWSRequest + + +/** +

The name of the dataset from which to unsubcribe.

+ */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** +

The unique ID generated for this device by Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable deviceId; + +/** +

Unique ID for this identity.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. The ID of the pool to which this identity belongs.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

Response to an UnsubscribeFromDataset request.

+ */ +@interface AWSCognitoSyncUnsubscribeFromDatasetResponse : AWSModel + + +@end + +/** + A request to post updates to records or add and delete records for a dataset and user. + Required parameters: [IdentityPoolId, IdentityId, DatasetName, SyncSessionToken] + */ +@interface AWSCognitoSyncUpdateRecordsRequest : AWSRequest + + +/** + Intended to supply a device ID that will populate the lastModifiedBy field referenced in other methods. The ClientContext field is not yet implemented. + */ +@property (nonatomic, strong) NSString * _Nullable clientContext; + +/** + A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot). + */ +@property (nonatomic, strong) NSString * _Nullable datasetName; + +/** +

The unique ID generated for this device by Cognito.

+ */ +@property (nonatomic, strong) NSString * _Nullable deviceId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + A list of patch operations. + */ +@property (nonatomic, strong) NSArray * _Nullable recordPatches; + +/** + The SyncSessionToken returned by a previous call to ListRecords for this dataset and identity. + */ +@property (nonatomic, strong) NSString * _Nullable syncSessionToken; + +@end + +/** + Returned for a successful UpdateRecordsRequest. + */ +@interface AWSCognitoSyncUpdateRecordsResponse : AWSModel + + +/** + A list of records that have been updated. + */ +@property (nonatomic, strong) NSArray * _Nullable records; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.m b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.m new file mode 100644 index 00000000..47bbab54 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncModel.m @@ -0,0 +1,722 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoSyncModel.h" +#import + +NSString *const AWSCognitoSyncErrorDomain = @"com.amazonaws.AWSCognitoSyncErrorDomain"; + +@implementation AWSCognitoSyncBulkPublishRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncBulkPublishResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncCognitoStreams + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"roleArn" : @"RoleArn", + @"streamName" : @"StreamName", + @"streamingStatus" : @"StreamingStatus", + }; +} + ++ (NSValueTransformer *)streamingStatusJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^NSNumber *(NSString *value) { + if ([value caseInsensitiveCompare:@"ENABLED"] == NSOrderedSame) { + return @(AWSCognitoSyncStreamingStatusEnabled); + } + if ([value caseInsensitiveCompare:@"DISABLED"] == NSOrderedSame) { + return @(AWSCognitoSyncStreamingStatusDisabled); + } + return @(AWSCognitoSyncStreamingStatusUnknown); + } reverseBlock:^NSString *(NSNumber *value) { + switch ([value integerValue]) { + case AWSCognitoSyncStreamingStatusEnabled: + return @"ENABLED"; + case AWSCognitoSyncStreamingStatusDisabled: + return @"DISABLED"; + default: + return nil; + } + }]; +} + +@end + +@implementation AWSCognitoSyncDataset + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"creationDate" : @"CreationDate", + @"dataStorage" : @"DataStorage", + @"datasetName" : @"DatasetName", + @"identityId" : @"IdentityId", + @"lastModifiedBy" : @"LastModifiedBy", + @"lastModifiedDate" : @"LastModifiedDate", + @"numRecords" : @"NumRecords", + }; +} + ++ (NSValueTransformer *)creationDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)lastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoSyncDeleteDatasetRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"datasetName" : @"DatasetName", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncDeleteDatasetResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"dataset" : @"Dataset", + }; +} + ++ (NSValueTransformer *)datasetJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncDataset class]]; +} + +@end + +@implementation AWSCognitoSyncDescribeDatasetRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"datasetName" : @"DatasetName", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncDescribeDatasetResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"dataset" : @"Dataset", + }; +} + ++ (NSValueTransformer *)datasetJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncDataset class]]; +} + +@end + +@implementation AWSCognitoSyncDescribeIdentityPoolUsageRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncDescribeIdentityPoolUsageResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolUsage" : @"IdentityPoolUsage", + }; +} + ++ (NSValueTransformer *)identityPoolUsageJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncIdentityPoolUsage class]]; +} + +@end + +@implementation AWSCognitoSyncDescribeIdentityUsageRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncDescribeIdentityUsageResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityUsage" : @"IdentityUsage", + }; +} + ++ (NSValueTransformer *)identityUsageJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncIdentityUsage class]]; +} + +@end + +@implementation AWSCognitoSyncGetBulkPublishDetailsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncGetBulkPublishDetailsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"bulkPublishCompleteTime" : @"BulkPublishCompleteTime", + @"bulkPublishStartTime" : @"BulkPublishStartTime", + @"bulkPublishStatus" : @"BulkPublishStatus", + @"failureMessage" : @"FailureMessage", + @"identityPoolId" : @"IdentityPoolId", + }; +} + ++ (NSValueTransformer *)bulkPublishCompleteTimeJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)bulkPublishStartTimeJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)bulkPublishStatusJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^NSNumber *(NSString *value) { + if ([value caseInsensitiveCompare:@"NOT_STARTED"] == NSOrderedSame) { + return @(AWSCognitoSyncBulkPublishStatusNotStarted); + } + if ([value caseInsensitiveCompare:@"IN_PROGRESS"] == NSOrderedSame) { + return @(AWSCognitoSyncBulkPublishStatusInProgress); + } + if ([value caseInsensitiveCompare:@"FAILED"] == NSOrderedSame) { + return @(AWSCognitoSyncBulkPublishStatusFailed); + } + if ([value caseInsensitiveCompare:@"SUCCEEDED"] == NSOrderedSame) { + return @(AWSCognitoSyncBulkPublishStatusSucceeded); + } + return @(AWSCognitoSyncBulkPublishStatusUnknown); + } reverseBlock:^NSString *(NSNumber *value) { + switch ([value integerValue]) { + case AWSCognitoSyncBulkPublishStatusNotStarted: + return @"NOT_STARTED"; + case AWSCognitoSyncBulkPublishStatusInProgress: + return @"IN_PROGRESS"; + case AWSCognitoSyncBulkPublishStatusFailed: + return @"FAILED"; + case AWSCognitoSyncBulkPublishStatusSucceeded: + return @"SUCCEEDED"; + default: + return nil; + } + }]; +} + +@end + +@implementation AWSCognitoSyncGetCognitoEventsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncGetCognitoEventsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"events" : @"Events", + }; +} + +@end + +@implementation AWSCognitoSyncGetIdentityPoolConfigurationRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncGetIdentityPoolConfigurationResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"cognitoStreams" : @"CognitoStreams", + @"identityPoolId" : @"IdentityPoolId", + @"pushSync" : @"PushSync", + }; +} + ++ (NSValueTransformer *)cognitoStreamsJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncCognitoStreams class]]; +} + ++ (NSValueTransformer *)pushSyncJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncPushSync class]]; +} + +@end + +@implementation AWSCognitoSyncIdentityPoolUsage + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"dataStorage" : @"DataStorage", + @"identityPoolId" : @"IdentityPoolId", + @"lastModifiedDate" : @"LastModifiedDate", + @"syncSessionsCount" : @"SyncSessionsCount", + }; +} + ++ (NSValueTransformer *)lastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoSyncIdentityUsage + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"dataStorage" : @"DataStorage", + @"datasetCount" : @"DatasetCount", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"lastModifiedDate" : @"LastModifiedDate", + }; +} + ++ (NSValueTransformer *)lastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoSyncListDatasetsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoSyncListDatasetsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"count" : @"Count", + @"datasets" : @"Datasets", + @"nextToken" : @"NextToken", + }; +} + ++ (NSValueTransformer *)datasetsJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoSyncDataset class]]; +} + +@end + +@implementation AWSCognitoSyncListIdentityPoolUsageRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoSyncListIdentityPoolUsageResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"count" : @"Count", + @"identityPoolUsages" : @"IdentityPoolUsages", + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + ++ (NSValueTransformer *)identityPoolUsagesJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoSyncIdentityPoolUsage class]]; +} + +@end + +@implementation AWSCognitoSyncListRecordsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"datasetName" : @"DatasetName", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"lastSyncCount" : @"LastSyncCount", + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + @"syncSessionToken" : @"SyncSessionToken", + }; +} + +@end + +@implementation AWSCognitoSyncListRecordsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"count" : @"Count", + @"datasetDeletedAfterRequestedSyncCount" : @"DatasetDeletedAfterRequestedSyncCount", + @"datasetExists" : @"DatasetExists", + @"datasetSyncCount" : @"DatasetSyncCount", + @"lastModifiedBy" : @"LastModifiedBy", + @"mergedDatasetNames" : @"MergedDatasetNames", + @"nextToken" : @"NextToken", + @"records" : @"Records", + @"syncSessionToken" : @"SyncSessionToken", + }; +} + ++ (NSValueTransformer *)recordsJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoSyncRecord class]]; +} + +@end + +@implementation AWSCognitoSyncPushSync + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"applicationArns" : @"ApplicationArns", + @"roleArn" : @"RoleArn", + }; +} + +@end + +@implementation AWSCognitoSyncRecord + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"deviceLastModifiedDate" : @"DeviceLastModifiedDate", + @"key" : @"Key", + @"lastModifiedBy" : @"LastModifiedBy", + @"lastModifiedDate" : @"LastModifiedDate", + @"syncCount" : @"SyncCount", + @"value" : @"Value", + }; +} + ++ (NSValueTransformer *)deviceLastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)lastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoSyncRecordPatch + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"deviceLastModifiedDate" : @"DeviceLastModifiedDate", + @"key" : @"Key", + @"op" : @"Op", + @"syncCount" : @"SyncCount", + @"value" : @"Value", + }; +} + ++ (NSValueTransformer *)deviceLastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)opJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^NSNumber *(NSString *value) { + if ([value caseInsensitiveCompare:@"replace"] == NSOrderedSame) { + return @(AWSCognitoSyncOperationReplace); + } + if ([value caseInsensitiveCompare:@"remove"] == NSOrderedSame) { + return @(AWSCognitoSyncOperationRemove); + } + return @(AWSCognitoSyncOperationUnknown); + } reverseBlock:^NSString *(NSNumber *value) { + switch ([value integerValue]) { + case AWSCognitoSyncOperationReplace: + return @"replace"; + case AWSCognitoSyncOperationRemove: + return @"remove"; + default: + return nil; + } + }]; +} + +@end + +@implementation AWSCognitoSyncRegisterDeviceRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"platform" : @"Platform", + @"token" : @"Token", + }; +} + ++ (NSValueTransformer *)platformJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^NSNumber *(NSString *value) { + if ([value caseInsensitiveCompare:@"APNS"] == NSOrderedSame) { + return @(AWSCognitoSyncPlatformApns); + } + if ([value caseInsensitiveCompare:@"APNS_SANDBOX"] == NSOrderedSame) { + return @(AWSCognitoSyncPlatformApnsSandbox); + } + if ([value caseInsensitiveCompare:@"GCM"] == NSOrderedSame) { + return @(AWSCognitoSyncPlatformGcm); + } + if ([value caseInsensitiveCompare:@"ADM"] == NSOrderedSame) { + return @(AWSCognitoSyncPlatformAdm); + } + return @(AWSCognitoSyncPlatformUnknown); + } reverseBlock:^NSString *(NSNumber *value) { + switch ([value integerValue]) { + case AWSCognitoSyncPlatformApns: + return @"APNS"; + case AWSCognitoSyncPlatformApnsSandbox: + return @"APNS_SANDBOX"; + case AWSCognitoSyncPlatformGcm: + return @"GCM"; + case AWSCognitoSyncPlatformAdm: + return @"ADM"; + default: + return nil; + } + }]; +} + +@end + +@implementation AWSCognitoSyncRegisterDeviceResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"deviceId" : @"DeviceId", + }; +} + +@end + +@implementation AWSCognitoSyncSetCognitoEventsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"events" : @"Events", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncSetIdentityPoolConfigurationRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"cognitoStreams" : @"CognitoStreams", + @"identityPoolId" : @"IdentityPoolId", + @"pushSync" : @"PushSync", + }; +} + ++ (NSValueTransformer *)cognitoStreamsJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncCognitoStreams class]]; +} + ++ (NSValueTransformer *)pushSyncJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncPushSync class]]; +} + +@end + +@implementation AWSCognitoSyncSetIdentityPoolConfigurationResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"cognitoStreams" : @"CognitoStreams", + @"identityPoolId" : @"IdentityPoolId", + @"pushSync" : @"PushSync", + }; +} + ++ (NSValueTransformer *)cognitoStreamsJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncCognitoStreams class]]; +} + ++ (NSValueTransformer *)pushSyncJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoSyncPushSync class]]; +} + +@end + +@implementation AWSCognitoSyncSubscribeToDatasetRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"datasetName" : @"DatasetName", + @"deviceId" : @"DeviceId", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncSubscribeToDatasetResponse + +@end + +@implementation AWSCognitoSyncUnsubscribeFromDatasetRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"datasetName" : @"DatasetName", + @"deviceId" : @"DeviceId", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoSyncUnsubscribeFromDatasetResponse + +@end + +@implementation AWSCognitoSyncUpdateRecordsRequest + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"clientContext" : @"ClientContext", + @"datasetName" : @"DatasetName", + @"deviceId" : @"DeviceId", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"recordPatches" : @"RecordPatches", + @"syncSessionToken" : @"SyncSessionToken", + }; +} + ++ (NSValueTransformer *)recordPatchesJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoSyncRecordPatch class]]; +} + +@end + +@implementation AWSCognitoSyncUpdateRecordsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"records" : @"Records", + }; +} + ++ (NSValueTransformer *)recordsJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoSyncRecord class]]; +} + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.h b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.h new file mode 100644 index 00000000..a4b1fa3b --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.h @@ -0,0 +1,24 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + +@interface AWSCognitoSyncResources : NSObject + ++ (instancetype)sharedInstance; + +- (NSDictionary *)JSONObject; + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.m b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.m new file mode 100644 index 00000000..d695466f --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncResources.m @@ -0,0 +1,1533 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoSyncResources.h" +#import + +@interface AWSCognitoSyncResources () + +@property (nonatomic, strong) NSDictionary *definitionDictionary; + +@end + +@implementation AWSCognitoSyncResources + ++ (instancetype)sharedInstance { + static AWSCognitoSyncResources *_sharedResources = nil; + static dispatch_once_t once_token; + + dispatch_once(&once_token, ^{ + _sharedResources = [AWSCognitoSyncResources new]; + }); + + return _sharedResources; +} + +- (NSDictionary *)JSONObject { + return self.definitionDictionary; +} + +- (instancetype)init { + if (self = [super init]) { + //init method + NSError *error = nil; + _definitionDictionary = [NSJSONSerialization JSONObjectWithData:[[self definitionString] dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:&error]; + if (_definitionDictionary == nil) { + if (error) { + AWSDDLogError(@"Failed to parse JSON service definition: %@",error); + } + } + } + return self; +} + +- (NSString *)definitionString { + return @"{\ + \"version\":\"2.0\",\ + \"metadata\":{\ + \"apiVersion\":\"2014-06-30\",\ + \"endpointPrefix\":\"cognito-sync\",\ + \"jsonVersion\":\"1.1\",\ + \"protocol\":\"rest-json\",\ + \"serviceFullName\":\"Amazon Cognito Sync\",\ + \"signatureVersion\":\"v4\"\ + },\ + \"operations\":{\ + \"BulkPublish\":{\ + \"name\":\"BulkPublish\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/bulkpublish\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"BulkPublishRequest\"},\ + \"output\":{\"shape\":\"BulkPublishResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"DuplicateRequestException\"},\ + {\"shape\":\"AlreadyStreamedException\"}\ + ],\ + \"documentation\":\"

Initiates a bulk publish of all existing datasets for an Identity Pool to the configured stream. Customers are limited to one successful bulk publish per 24 hours. Bulk publish is an asynchronous request, customers can see the status of the request via the GetBulkPublishDetails operation.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"DeleteDataset\":{\ + \"name\":\"DeleteDataset\",\ + \"http\":{\ + \"method\":\"DELETE\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"DeleteDatasetRequest\"},\ + \"output\":{\"shape\":\"DeleteDatasetResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"ResourceConflictException\"}\ + ],\ + \"documentation\":\"

Deletes the specific dataset. The dataset will be deleted permanently, and the action can't be undone. Datasets that this dataset was merged with will no longer report the merge. Any subsequent operation on this dataset will result in a ResourceNotFoundException.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

\"\ + },\ + \"DescribeDataset\":{\ + \"name\":\"DescribeDataset\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"DescribeDatasetRequest\"},\ + \"output\":{\"shape\":\"DescribeDatasetResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets meta data about a dataset by identity and dataset name. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

\"\ + },\ + \"DescribeIdentityPoolUsage\":{\ + \"name\":\"DescribeIdentityPoolUsage\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"DescribeIdentityPoolUsageRequest\"},\ + \"output\":{\"shape\":\"DescribeIdentityPoolUsageResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets usage details (for example, data storage) about a particular identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"DescribeIdentityUsage\":{\ + \"name\":\"DescribeIdentityUsage\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"DescribeIdentityUsageRequest\"},\ + \"output\":{\"shape\":\"DescribeIdentityUsageResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets usage information for an identity, including number of datasets and data usage.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

\"\ + },\ + \"GetBulkPublishDetails\":{\ + \"name\":\"GetBulkPublishDetails\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/getBulkPublishDetails\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"GetBulkPublishDetailsRequest\"},\ + \"output\":{\"shape\":\"GetBulkPublishDetailsResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Get the status of the last BulkPublish operation for an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"GetCognitoEvents\":{\ + \"name\":\"GetCognitoEvents\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/events\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"GetCognitoEventsRequest\"},\ + \"output\":{\"shape\":\"GetCognitoEventsResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets the events and the corresponding Lambda functions associated with an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"GetIdentityPoolConfiguration\":{\ + \"name\":\"GetIdentityPoolConfiguration\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/configuration\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"GetIdentityPoolConfigurationRequest\"},\ + \"output\":{\"shape\":\"GetIdentityPoolConfigurationResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets the configuration settings of an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"ListDatasets\":{\ + \"name\":\"ListDatasets\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"ListDatasetsRequest\"},\ + \"output\":{\"shape\":\"ListDatasetsResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Lists datasets for an identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListDatasets can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use the Cognito Identity credentials to make this API call.

\"\ + },\ + \"ListIdentityPoolUsage\":{\ + \"name\":\"ListIdentityPoolUsage\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"ListIdentityPoolUsageRequest\"},\ + \"output\":{\"shape\":\"ListIdentityPoolUsageResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Gets a list of identity pools registered with Cognito.

ListIdentityPoolUsage can only be called with developer credentials. You cannot make this API call with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"ListRecords\":{\ + \"name\":\"ListRecords\",\ + \"http\":{\ + \"method\":\"GET\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/records\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"ListRecordsRequest\"},\ + \"output\":{\"shape\":\"ListRecordsResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Gets paginated records, optionally changed after a particular sync count for a dataset and identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListRecords can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

\"\ + },\ + \"RegisterDevice\":{\ + \"name\":\"RegisterDevice\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identity/{IdentityId}/device\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"RegisterDeviceRequest\"},\ + \"output\":{\"shape\":\"RegisterDeviceResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"InvalidConfigurationException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Registers a device to receive push sync notifications.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

\"\ + },\ + \"SetCognitoEvents\":{\ + \"name\":\"SetCognitoEvents\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/events\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"SetCognitoEventsRequest\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Sets the AWS Lambda function for a given event type for an identity pool. This request only updates the key/value pair specified. Other key/values pairs are not updated. To remove a key value pair, pass a empty value for the particular key.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"SetIdentityPoolConfiguration\":{\ + \"name\":\"SetIdentityPoolConfiguration\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/configuration\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"SetIdentityPoolConfigurationRequest\"},\ + \"output\":{\"shape\":\"SetIdentityPoolConfigurationResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"ConcurrentModificationException\"}\ + ],\ + \"documentation\":\"

Sets the necessary configuration for push sync.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

\"\ + },\ + \"SubscribeToDataset\":{\ + \"name\":\"SubscribeToDataset\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/subscriptions/{DeviceId}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"SubscribeToDatasetRequest\"},\ + \"output\":{\"shape\":\"SubscribeToDatasetResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"InvalidConfigurationException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Subscribes to receive notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

\"\ + },\ + \"UnsubscribeFromDataset\":{\ + \"name\":\"UnsubscribeFromDataset\",\ + \"http\":{\ + \"method\":\"DELETE\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/subscriptions/{DeviceId}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"UnsubscribeFromDatasetRequest\"},\ + \"output\":{\"shape\":\"UnsubscribeFromDatasetResponse\"},\ + \"errors\":[\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"InvalidConfigurationException\"},\ + {\"shape\":\"TooManyRequestsException\"}\ + ],\ + \"documentation\":\"

Unsubscribes from receiving notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

\"\ + },\ + \"UpdateRecords\":{\ + \"name\":\"UpdateRecords\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}\",\ + \"responseCode\":200\ + },\ + \"input\":{\"shape\":\"UpdateRecordsRequest\"},\ + \"output\":{\"shape\":\"UpdateRecordsResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"LimitExceededException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"InvalidLambdaFunctionOutputException\"},\ + {\"shape\":\"LambdaThrottledException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Posts updates to records and adds and deletes records for a dataset and user.

The sync count in the record patch is your last known sync count for that record. The server will reject an UpdateRecords request with a ResourceConflictException if you try to patch a record with a new value but a stale sync count.

For example, if the sync count on the server is 5 for a key called highScore and you try and submit a new highScore with sync count of 4, the request will be rejected. To obtain the current sync count for a record, call ListRecords. On a successful update of the record, the response returns the new sync count for that record. You should present that sync count the next time you try to update that same record. When the record does not exist, specify the sync count as 0.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

\"\ + }\ + },\ + \"shapes\":{\ + \"AlreadyStreamedException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"The message associated with the AlreadyStreamedException exception.\"\ + }\ + },\ + \"documentation\":\"An exception thrown when a bulk publish operation is requested less than 24 hours after a previous bulk publish operation completed successfully.\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"ApplicationArn\":{\ + \"type\":\"string\",\ + \"pattern\":\"arn:aws:sns:[-0-9a-z]+:\\\\d+:app/[A-Z_]+/[a-zA-Z0-9_.-]+\"\ + },\ + \"ApplicationArnList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"ApplicationArn\"}\ + },\ + \"AssumeRoleArn\":{\ + \"type\":\"string\",\ + \"max\":2048,\ + \"min\":20,\ + \"pattern\":\"arn:aws:iam::\\\\d+:role/.*\"\ + },\ + \"Boolean\":{\"type\":\"boolean\"},\ + \"BulkPublishRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + }\ + },\ + \"documentation\":\"The input for the BulkPublish operation.\"\ + },\ + \"BulkPublishResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + }\ + },\ + \"documentation\":\"The output for the BulkPublish operation.\"\ + },\ + \"BulkPublishStatus\":{\ + \"type\":\"string\",\ + \"enum\":[\ + \"NOT_STARTED\",\ + \"IN_PROGRESS\",\ + \"FAILED\",\ + \"SUCCEEDED\"\ + ]\ + },\ + \"ClientContext\":{\"type\":\"string\"},\ + \"CognitoEventType\":{\"type\":\"string\"},\ + \"CognitoStreams\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"StreamName\":{\ + \"shape\":\"StreamName\",\ + \"documentation\":\"The name of the Cognito stream to receive updates. This stream must be in the developers account and in the same region as the identity pool.\"\ + },\ + \"RoleArn\":{\ + \"shape\":\"AssumeRoleArn\",\ + \"documentation\":\"The ARN of the role Amazon Cognito can assume in order to publish to the stream. This role must grant access to Amazon Cognito (cognito-sync) to invoke PutRecord on your Cognito stream.\"\ + },\ + \"StreamingStatus\":{\ + \"shape\":\"StreamingStatus\",\ + \"documentation\":\"Status of the Cognito streams. Valid values are:

ENABLED - Streaming of updates to identity pool is enabled.

DISABLED - Streaming of updates to identity pool is disabled. Bulk publish will also fail if StreamingStatus is DISABLED.

\"\ + }\ + },\ + \"documentation\":\"Configuration options for configure Cognito streams.\"\ + },\ + \"ConcurrentModificationException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"

The message returned by a ConcurrentModicationException.

\"\ + }\ + },\ + \"documentation\":\"

Thrown if there are parallel requests to modify a resource.

\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"Dataset\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot).\"\ + },\ + \"CreationDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"Date on which the dataset was created.\"\ + },\ + \"LastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"Date when the dataset was last modified.\"\ + },\ + \"LastModifiedBy\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The device that made the last change to this dataset.\"\ + },\ + \"DataStorage\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Total size in bytes of the records in this dataset.\"\ + },\ + \"NumRecords\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Number of records in this dataset.\"\ + }\ + },\ + \"documentation\":\"A collection of data for an identity pool. An identity pool can have multiple datasets. A dataset is per identity and can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs.\"\ + },\ + \"DatasetList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"Dataset\"}\ + },\ + \"DatasetName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[a-zA-Z0-9_.:-]+\"\ + },\ + \"Date\":{\"type\":\"timestamp\"},\ + \"DeleteDatasetRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot).\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + }\ + },\ + \"documentation\":\"A request to delete the specific dataset.\"\ + },\ + \"DeleteDatasetResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Dataset\":{\ + \"shape\":\"Dataset\",\ + \"documentation\":\"A collection of data for an identity pool. An identity pool can have multiple datasets. A dataset is per identity and can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs.\"\ + }\ + },\ + \"documentation\":\"Response to a successful DeleteDataset request.\"\ + },\ + \"DescribeDatasetRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot).\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + }\ + },\ + \"documentation\":\"A request for meta data about a dataset (creation date, number of records, size) by owner and dataset name.\"\ + },\ + \"DescribeDatasetResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Dataset\":{\ + \"shape\":\"Dataset\",\ + \"documentation\":\"Meta data for a collection of data for an identity. An identity can have multiple datasets. A dataset can be general or associated with a particular entity in an application (like a saved game). Datasets are automatically created if they don't exist. Data is synced by dataset, and a dataset can hold up to 1MB of key-value pairs.\"\ + }\ + },\ + \"documentation\":\"Response to a successful DescribeDataset request.\"\ + },\ + \"DescribeIdentityPoolUsageRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + }\ + },\ + \"documentation\":\"A request for usage information about the identity pool.\"\ + },\ + \"DescribeIdentityPoolUsageResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolUsage\":{\ + \"shape\":\"IdentityPoolUsage\",\ + \"documentation\":\"Information about the usage of the identity pool.\"\ + }\ + },\ + \"documentation\":\"Response to a successful DescribeIdentityPoolUsage request.\"\ + },\ + \"DescribeIdentityUsageRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + }\ + },\ + \"documentation\":\"A request for information about the usage of an identity pool.\"\ + },\ + \"DescribeIdentityUsageResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityUsage\":{\ + \"shape\":\"IdentityUsage\",\ + \"documentation\":\"Usage information for the identity.\"\ + }\ + },\ + \"documentation\":\"The response to a successful DescribeIdentityUsage request.\"\ + },\ + \"DeviceId\":{\ + \"type\":\"string\",\ + \"max\":256,\ + \"min\":1\ + },\ + \"DuplicateRequestException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"The message associated with the DuplicateRequestException exception.\"\ + }\ + },\ + \"documentation\":\"An exception thrown when there is an IN_PROGRESS bulk publish operation for the given identity pool.\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"Events\":{\ + \"type\":\"map\",\ + \"key\":{\"shape\":\"CognitoEventType\"},\ + \"value\":{\"shape\":\"LambdaFunctionArn\"},\ + \"max\":1\ + },\ + \"ExceptionMessage\":{\"type\":\"string\"},\ + \"GetBulkPublishDetailsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + }\ + },\ + \"documentation\":\"The input for the GetBulkPublishDetails operation.\"\ + },\ + \"GetBulkPublishDetailsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + },\ + \"BulkPublishStartTime\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"The date/time at which the last bulk publish was initiated.\"\ + },\ + \"BulkPublishCompleteTime\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"If BulkPublishStatus is SUCCEEDED, the time the last bulk publish operation completed.\"\ + },\ + \"BulkPublishStatus\":{\ + \"shape\":\"BulkPublishStatus\",\ + \"documentation\":\"Status of the last bulk publish operation, valid values are:

NOT_STARTED - No bulk publish has been requested for this identity pool

IN_PROGRESS - Data is being published to the configured stream

SUCCEEDED - All data for the identity pool has been published to the configured stream

FAILED - Some portion of the data has failed to publish, check FailureMessage for the cause.

\"\ + },\ + \"FailureMessage\":{\ + \"shape\":\"String\",\ + \"documentation\":\"If BulkPublishStatus is FAILED this field will contain the error message that caused the bulk publish to fail.\"\ + }\ + },\ + \"documentation\":\"The output for the GetBulkPublishDetails operation.\"\ + },\ + \"GetCognitoEventsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

The Cognito Identity Pool ID for the request

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + }\ + },\ + \"documentation\":\"

A request for a list of the configured Cognito Events

\"\ + },\ + \"GetCognitoEventsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Events\":{\ + \"shape\":\"Events\",\ + \"documentation\":\"

The Cognito Events returned from the GetCognitoEvents request

\"\ + }\ + },\ + \"documentation\":\"

The response from the GetCognitoEvents request

\"\ + },\ + \"GetIdentityPoolConfigurationRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. This is the ID of the pool for which to return a configuration.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + }\ + },\ + \"documentation\":\"

The input for the GetIdentityPoolConfiguration operation.

\"\ + },\ + \"GetIdentityPoolConfigurationResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito.

\"\ + },\ + \"PushSync\":{\ + \"shape\":\"PushSync\",\ + \"documentation\":\"

Options to apply to this identity pool for push synchronization.

\"\ + },\ + \"CognitoStreams\":{\ + \"shape\":\"CognitoStreams\",\ + \"documentation\":\"Options to apply to this identity pool for Amazon Cognito streams.\"\ + }\ + },\ + \"documentation\":\"

The output for the GetIdentityPoolConfiguration operation.

\"\ + },\ + \"IdentityId\":{\ + \"type\":\"string\",\ + \"max\":55,\ + \"min\":1,\ + \"pattern\":\"[\\\\w-]+:[0-9a-f-]+\"\ + },\ + \"IdentityPoolId\":{\ + \"type\":\"string\",\ + \"max\":55,\ + \"min\":1,\ + \"pattern\":\"[\\\\w-]+:[0-9a-f-]+\"\ + },\ + \"IdentityPoolUsage\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + },\ + \"SyncSessionsCount\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Number of sync sessions for the identity pool.\"\ + },\ + \"DataStorage\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Data storage information for the identity pool.\"\ + },\ + \"LastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"Date on which the identity pool was last modified.\"\ + }\ + },\ + \"documentation\":\"Usage information for the identity pool.\"\ + },\ + \"IdentityPoolUsageList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"IdentityPoolUsage\"}\ + },\ + \"IdentityUsage\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + },\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\"\ + },\ + \"LastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"Date on which the identity was last modified.\"\ + },\ + \"DatasetCount\":{\ + \"shape\":\"Integer\",\ + \"documentation\":\"Number of datasets for the identity.\"\ + },\ + \"DataStorage\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Total data storage for this identity.\"\ + }\ + },\ + \"documentation\":\"Usage information for the identity.\"\ + },\ + \"Integer\":{\"type\":\"integer\"},\ + \"IntegerString\":{\"type\":\"integer\"},\ + \"InternalErrorException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by InternalErrorException.\"\ + }\ + },\ + \"documentation\":\"Indicates an internal service error.\",\ + \"error\":{\"httpStatusCode\":500},\ + \"exception\":true,\ + \"fault\":true\ + },\ + \"InvalidConfigurationException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by InvalidConfigurationException.\"\ + }\ + },\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"InvalidLambdaFunctionOutputException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"

A message returned when an InvalidLambdaFunctionOutputException occurs

\"\ + }\ + },\ + \"documentation\":\"

The AWS Lambda function returned invalid output or an exception.

\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"InvalidParameterException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by InvalidParameterException.\"\ + }\ + },\ + \"documentation\":\"Thrown when a request parameter does not comply with the associated constraints.\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"LambdaFunctionArn\":{\"type\":\"string\"},\ + \"LambdaThrottledException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"

A message returned when an LambdaThrottledException is thrown

\"\ + }\ + },\ + \"documentation\":\"

AWS Lambda throttled your account, please contact AWS Support

\",\ + \"error\":{\"httpStatusCode\":429},\ + \"exception\":true\ + },\ + \"LimitExceededException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by LimitExceededException.\"\ + }\ + },\ + \"documentation\":\"Thrown when the limit on the number of objects or operations has been exceeded.\",\ + \"error\":{\"httpStatusCode\":400},\ + \"exception\":true\ + },\ + \"ListDatasetsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityId\",\ + \"IdentityPoolId\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"nextToken\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"IntegerString\",\ + \"documentation\":\"The maximum number of results to be returned.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"maxResults\"\ + }\ + },\ + \"documentation\":\"Request for a list of datasets for an identity.\"\ + },\ + \"ListDatasetsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Datasets\":{\ + \"shape\":\"DatasetList\",\ + \"documentation\":\"A set of datasets.\"\ + },\ + \"Count\":{\ + \"shape\":\"Integer\",\ + \"documentation\":\"Number of datasets returned.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\"\ + }\ + },\ + \"documentation\":\"Returned for a successful ListDatasets request.\"\ + },\ + \"ListIdentityPoolUsageRequest\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"nextToken\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"IntegerString\",\ + \"documentation\":\"The maximum number of results to be returned.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"maxResults\"\ + }\ + },\ + \"documentation\":\"A request for usage information on an identity pool.\"\ + },\ + \"ListIdentityPoolUsageResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolUsages\":{\ + \"shape\":\"IdentityPoolUsageList\",\ + \"documentation\":\"Usage information for the identity pools.\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"Integer\",\ + \"documentation\":\"The maximum number of results to be returned.\"\ + },\ + \"Count\":{\ + \"shape\":\"Integer\",\ + \"documentation\":\"Total number of identities for the identity pool.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\"\ + }\ + },\ + \"documentation\":\"Returned for a successful ListIdentityPoolUsage request.\"\ + },\ + \"ListRecordsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot).\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + },\ + \"LastSyncCount\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"The last server sync count for this record.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"lastSyncCount\"\ + },\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"nextToken\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"IntegerString\",\ + \"documentation\":\"The maximum number of results to be returned.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"maxResults\"\ + },\ + \"SyncSessionToken\":{\ + \"shape\":\"SyncSessionToken\",\ + \"documentation\":\"A token containing a session ID, identity ID, and expiration.\",\ + \"location\":\"querystring\",\ + \"locationName\":\"syncSessionToken\"\ + }\ + },\ + \"documentation\":\"A request for a list of records.\"\ + },\ + \"ListRecordsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Records\":{\ + \"shape\":\"RecordList\",\ + \"documentation\":\"A list of all records.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A pagination token for obtaining the next page of results.\"\ + },\ + \"Count\":{\ + \"shape\":\"Integer\",\ + \"documentation\":\"Total number of records.\"\ + },\ + \"DatasetSyncCount\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Server sync count for this dataset.\"\ + },\ + \"LastModifiedBy\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The user/device that made the last change to this record.\"\ + },\ + \"MergedDatasetNames\":{\ + \"shape\":\"MergedDatasetNameList\",\ + \"documentation\":\"Names of merged datasets.\"\ + },\ + \"DatasetExists\":{\ + \"shape\":\"Boolean\",\ + \"documentation\":\"Indicates whether the dataset exists.\"\ + },\ + \"DatasetDeletedAfterRequestedSyncCount\":{\ + \"shape\":\"Boolean\",\ + \"documentation\":\"A boolean value specifying whether to delete the dataset locally.\"\ + },\ + \"SyncSessionToken\":{\ + \"shape\":\"String\",\ + \"documentation\":\"A token containing a session ID, identity ID, and expiration.\"\ + }\ + },\ + \"documentation\":\"Returned for a successful ListRecordsRequest.\"\ + },\ + \"Long\":{\"type\":\"long\"},\ + \"MergedDatasetNameList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"String\"}\ + },\ + \"NotAuthorizedException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"The message returned by a NotAuthorizedException.\"\ + }\ + },\ + \"documentation\":\"Thrown when a user is not authorized to access the requested resource.\",\ + \"error\":{\"httpStatusCode\":403},\ + \"exception\":true\ + },\ + \"Operation\":{\ + \"type\":\"string\",\ + \"enum\":[\ + \"replace\",\ + \"remove\"\ + ]\ + },\ + \"Platform\":{\ + \"type\":\"string\",\ + \"enum\":[\ + \"APNS\",\ + \"APNS_SANDBOX\",\ + \"GCM\",\ + \"ADM\"\ + ]\ + },\ + \"PushSync\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"ApplicationArns\":{\ + \"shape\":\"ApplicationArnList\",\ + \"documentation\":\"

List of SNS platform application ARNs that could be used by clients.

\"\ + },\ + \"RoleArn\":{\ + \"shape\":\"AssumeRoleArn\",\ + \"documentation\":\"

A role configured to allow Cognito to call SNS on behalf of the developer.

\"\ + }\ + },\ + \"documentation\":\"

Configuration options to be applied to the identity pool.

\"\ + },\ + \"PushToken\":{\"type\":\"string\"},\ + \"Record\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Key\":{\ + \"shape\":\"RecordKey\",\ + \"documentation\":\"The key for the record.\"\ + },\ + \"Value\":{\ + \"shape\":\"RecordValue\",\ + \"documentation\":\"The value for the record.\"\ + },\ + \"SyncCount\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"The server sync count for this record.\"\ + },\ + \"LastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"The date on which the record was last modified.\"\ + },\ + \"LastModifiedBy\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The user/device that made the last change to this record.\"\ + },\ + \"DeviceLastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"The last modified date of the client device.\"\ + }\ + },\ + \"documentation\":\"The basic data structure of a dataset.\"\ + },\ + \"RecordKey\":{\ + \"type\":\"string\",\ + \"max\":1024,\ + \"min\":1\ + },\ + \"RecordList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"Record\"}\ + },\ + \"RecordPatch\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"Op\",\ + \"Key\",\ + \"SyncCount\"\ + ],\ + \"members\":{\ + \"Op\":{\ + \"shape\":\"Operation\",\ + \"documentation\":\"An operation, either replace or remove.\"\ + },\ + \"Key\":{\ + \"shape\":\"RecordKey\",\ + \"documentation\":\"The key associated with the record patch.\"\ + },\ + \"Value\":{\ + \"shape\":\"RecordValue\",\ + \"documentation\":\"The value associated with the record patch.\"\ + },\ + \"SyncCount\":{\ + \"shape\":\"Long\",\ + \"documentation\":\"Last known server sync count for this record. Set to 0 if unknown.\"\ + },\ + \"DeviceLastModifiedDate\":{\ + \"shape\":\"Date\",\ + \"documentation\":\"The last modified date of the client device.\"\ + }\ + },\ + \"documentation\":\"An update operation for a record.\"\ + },\ + \"RecordPatchList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"RecordPatch\"}\ + },\ + \"RecordValue\":{\ + \"type\":\"string\",\ + \"max\":1048575\ + },\ + \"RegisterDeviceRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"Platform\",\ + \"Token\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. Here, the ID of the pool that the identity belongs to.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

The unique ID for this identity.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"Platform\":{\ + \"shape\":\"Platform\",\ + \"documentation\":\"

The SNS platform type (e.g. GCM, SDM, APNS, APNS_SANDBOX).

\"\ + },\ + \"Token\":{\ + \"shape\":\"PushToken\",\ + \"documentation\":\"

The push token.

\"\ + }\ + },\ + \"documentation\":\"

A request to RegisterDevice.

\"\ + },\ + \"RegisterDeviceResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"DeviceId\":{\ + \"shape\":\"DeviceId\",\ + \"documentation\":\"

The unique ID generated for this device by Cognito.

\"\ + }\ + },\ + \"documentation\":\"

Response to a RegisterDevice request.

\"\ + },\ + \"ResourceConflictException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"The message returned by a ResourceConflictException.\"\ + }\ + },\ + \"documentation\":\"Thrown if an update can't be applied because the resource was changed by another call and this would result in a conflict.\",\ + \"error\":{\"httpStatusCode\":409},\ + \"exception\":true\ + },\ + \"ResourceNotFoundException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by a ResourceNotFoundException.\"\ + }\ + },\ + \"documentation\":\"Thrown if the resource doesn't exist.\",\ + \"error\":{\"httpStatusCode\":404},\ + \"exception\":true\ + },\ + \"SetCognitoEventsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"Events\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

The Cognito Identity Pool to use when configuring Cognito Events

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"Events\":{\ + \"shape\":\"Events\",\ + \"documentation\":\"

The events to configure

\"\ + }\ + },\ + \"documentation\":\"

A request to configure Cognito Events\\\"

\\\"\"\ + },\ + \"SetIdentityPoolConfigurationRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. This is the ID of the pool to modify.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"PushSync\":{\ + \"shape\":\"PushSync\",\ + \"documentation\":\"

Options to apply to this identity pool for push synchronization.

\"\ + },\ + \"CognitoStreams\":{\ + \"shape\":\"CognitoStreams\",\ + \"documentation\":\"Options to apply to this identity pool for Amazon Cognito streams.\"\ + }\ + },\ + \"documentation\":\"

The input for the SetIdentityPoolConfiguration operation.

\"\ + },\ + \"SetIdentityPoolConfigurationResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito.

\"\ + },\ + \"PushSync\":{\ + \"shape\":\"PushSync\",\ + \"documentation\":\"

Options to apply to this identity pool for push synchronization.

\"\ + },\ + \"CognitoStreams\":{\ + \"shape\":\"CognitoStreams\",\ + \"documentation\":\"Options to apply to this identity pool for Amazon Cognito streams.\"\ + }\ + },\ + \"documentation\":\"

The output for the SetIdentityPoolConfiguration operation

\"\ + },\ + \"StreamName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1\ + },\ + \"StreamingStatus\":{\ + \"type\":\"string\",\ + \"enum\":[\ + \"ENABLED\",\ + \"DISABLED\"\ + ]\ + },\ + \"String\":{\"type\":\"string\"},\ + \"SubscribeToDatasetRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\",\ + \"DeviceId\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. The ID of the pool to which the identity belongs.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

Unique ID for this identity.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"

The name of the dataset to subcribe to.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + },\ + \"DeviceId\":{\ + \"shape\":\"DeviceId\",\ + \"documentation\":\"

The unique ID generated for this device by Cognito.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"DeviceId\"\ + }\ + },\ + \"documentation\":\"

A request to SubscribeToDatasetRequest.

\"\ + },\ + \"SubscribeToDatasetResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + },\ + \"documentation\":\"

Response to a SubscribeToDataset request.

\"\ + },\ + \"SyncSessionToken\":{\"type\":\"string\"},\ + \"TooManyRequestsException\":{\ + \"type\":\"structure\",\ + \"required\":[\"message\"],\ + \"members\":{\ + \"message\":{\ + \"shape\":\"ExceptionMessage\",\ + \"documentation\":\"Message returned by a TooManyRequestsException.\"\ + }\ + },\ + \"documentation\":\"Thrown if the request is throttled.\",\ + \"error\":{\"httpStatusCode\":429},\ + \"exception\":true\ + },\ + \"UnsubscribeFromDatasetRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\",\ + \"DeviceId\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. The ID of the pool to which this identity belongs.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

Unique ID for this identity.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"

The name of the dataset from which to unsubcribe.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + },\ + \"DeviceId\":{\ + \"shape\":\"DeviceId\",\ + \"documentation\":\"

The unique ID generated for this device by Cognito.

\",\ + \"location\":\"uri\",\ + \"locationName\":\"DeviceId\"\ + }\ + },\ + \"documentation\":\"

A request to UnsubscribeFromDataset.

\"\ + },\ + \"UnsubscribeFromDatasetResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + },\ + \"documentation\":\"

Response to an UnsubscribeFromDataset request.

\"\ + },\ + \"UpdateRecordsRequest\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityId\",\ + \"DatasetName\",\ + \"SyncSessionToken\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityPoolId\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A name-spaced GUID (for example, us-east-1:23EC4050-6AEA-7089-A2DD-08002EXAMPLE) created by Amazon Cognito. GUID generation is unique within a region.\",\ + \"location\":\"uri\",\ + \"locationName\":\"IdentityId\"\ + },\ + \"DatasetName\":{\ + \"shape\":\"DatasetName\",\ + \"documentation\":\"A string of up to 128 characters. Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (dash), and '.' (dot).\",\ + \"location\":\"uri\",\ + \"locationName\":\"DatasetName\"\ + },\ + \"DeviceId\":{\ + \"shape\":\"DeviceId\",\ + \"documentation\":\"

The unique ID generated for this device by Cognito.

\"\ + },\ + \"RecordPatches\":{\ + \"shape\":\"RecordPatchList\",\ + \"documentation\":\"A list of patch operations.\"\ + },\ + \"SyncSessionToken\":{\ + \"shape\":\"SyncSessionToken\",\ + \"documentation\":\"The SyncSessionToken returned by a previous call to ListRecords for this dataset and identity.\"\ + },\ + \"ClientContext\":{\ + \"shape\":\"ClientContext\",\ + \"documentation\":\"Intended to supply a device ID that will populate the lastModifiedBy field referenced in other methods. The ClientContext field is not yet implemented.\",\ + \"location\":\"header\",\ + \"locationName\":\"x-amz-Client-Context\"\ + }\ + },\ + \"documentation\":\"A request to post updates to records or add and delete records for a dataset and user.\"\ + },\ + \"UpdateRecordsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"Records\":{\ + \"shape\":\"RecordList\",\ + \"documentation\":\"A list of records that have been updated.\"\ + }\ + },\ + \"documentation\":\"Returned for a successful UpdateRecordsRequest.\"\ + }\ + },\ + \"documentation\":\"Amazon Cognito Sync

Amazon Cognito Sync provides an AWS service and client library that enable cross-device syncing of application-related user data. High-level client libraries are available for both iOS and Android. You can use these libraries to persist data locally so that it's available even if the device is offline. Developer credentials don't need to be stored on the mobile device to access the service. You can use Amazon Cognito to obtain a normalized user ID and credentials. User data is persisted in a dataset that can store up to 1 MB of key-value pairs, and you can have up to 20 datasets per user identity.

With Amazon Cognito Sync, the data stored for each identity is accessible only to credentials assigned to that identity. In order to use the Cognito Sync service, you need to make API calls using credentials retrieved with Amazon Cognito Identity service.

If you want to use Cognito Sync in an Android or iOS application, you will probably want to make API calls via the AWS Mobile SDK. To learn more, see the Developer Guide for Android and the Developer Guide for iOS.

\"\ +}\ +"; +} + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.h b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.h new file mode 100644 index 00000000..ab5d537a --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.h @@ -0,0 +1,598 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import +#import "AWSCognitoSyncModel.h" +#import "AWSCognitoSyncResources.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Amazon Cognito Sync

Amazon Cognito Sync provides an AWS service and client library that enable cross-device syncing of application-related user data. High-level client libraries are available for both iOS and Android. You can use these libraries to persist data locally so that it's available even if the device is offline. Developer credentials don't need to be stored on the mobile device to access the service. You can use Amazon Cognito to obtain a normalized user ID and credentials. User data is persisted in a dataset that can store up to 1 MB of key-value pairs, and you can have up to 20 datasets per user identity.

With Amazon Cognito Sync, the data stored for each identity is accessible only to credentials assigned to that identity. In order to use the Cognito Sync service, you need to make API calls using credentials retrieved with Amazon Cognito Identity service.

If you want to use Cognito Sync in an Android or iOS application, you will probably want to make API calls via the AWS Mobile SDK. To learn more, see the Developer Guide for Android and the Developer Guide for iOS.

+ */ +@interface AWSCognitoSync : AWSService + +/** + The service configuration used to instantiate this service client. + + @warning Once the client is instantiated, do not modify the configuration object. It may cause unspecified behaviors. + */ +@property (nonatomic, strong, readonly) AWSServiceConfiguration *configuration; + +/** + Returns the singleton service client. If the singleton object does not exist, the SDK instantiates the default service client with `defaultServiceConfiguration` from `[AWSServiceManager defaultServiceManager]`. The reference to this object is maintained by the SDK, and you do not need to retain it manually. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialProvider) + AWSServiceManager.default().defaultServiceConfiguration = configuration + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 + credentialsProvider:credentialsProvider]; + [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration; + + return YES; + } + + Then call the following to get the default service client: + + *Swift* + + let CognitoSync = AWSCognitoSync.default() + + *Objective-C* + + AWSCognitoSync *CognitoSync = [AWSCognitoSync defaultCognitoSync]; + + @return The default service client. + */ ++ (instancetype)defaultCognitoSync; + +/** + Creates a service client with the given service configuration and registers it for the key. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognitoSync.register(with: configuration!, forKey: "USWest2CognitoSync") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognitoSync registerCognitoSyncWithConfiguration:configuration forKey:@"USWest2CognitoSync"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let CognitoSync = AWSCognitoSync(forKey: "USWest2CognitoSync") + + *Objective-C* + + AWSCognitoSync *CognitoSync = [AWSCognitoSync CognitoSyncForKey:@"USWest2CognitoSync"]; + + @warning After calling this method, do not modify the configuration object. It may cause unspecified behaviors. + + @param configuration A service configuration object. + @param key A string to identify the service client. + */ ++ (void)registerCognitoSyncWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key; + +/** + Retrieves the service client associated with the key. You need to call `+ registerCognitoSyncWithConfiguration:forKey:` before invoking this method. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognitoSync.register(with: configuration!, forKey: "USWest2CognitoSync") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognitoSync registerCognitoSyncWithConfiguration:configuration forKey:@"USWest2CognitoSync"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let CognitoSync = AWSCognitoSync(forKey: "USWest2CognitoSync") + + *Objective-C* + + AWSCognitoSync *CognitoSync = [AWSCognitoSync CognitoSyncForKey:@"USWest2CognitoSync"]; + + @param key A string to identify the service client. + + @return An instance of the service client. + */ ++ (instancetype)CognitoSyncForKey:(NSString *)key; + +/** + Removes the service client associated with the key and release it. + + @warning Before calling this method, make sure no method is running on this client. + + @param key A string to identify the service client. + */ ++ (void)removeCognitoSyncForKey:(NSString *)key; + +/** +

Initiates a bulk publish of all existing datasets for an Identity Pool to the configured stream. Customers are limited to one successful bulk publish per 24 hours. Bulk publish is an asynchronous request, customers can see the status of the request via the GetBulkPublishDetails operation.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the BulkPublish service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncBulkPublishResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorDuplicateRequest`, `AWSCognitoSyncErrorAlreadyStreamed`. + + @see AWSCognitoSyncBulkPublishRequest + @see AWSCognitoSyncBulkPublishResponse + */ +- (AWSTask *)bulkPublish:(AWSCognitoSyncBulkPublishRequest *)request; + +/** +

Initiates a bulk publish of all existing datasets for an Identity Pool to the configured stream. Customers are limited to one successful bulk publish per 24 hours. Bulk publish is an asynchronous request, customers can see the status of the request via the GetBulkPublishDetails operation.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the BulkPublish service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorDuplicateRequest`, `AWSCognitoSyncErrorAlreadyStreamed`. + + @see AWSCognitoSyncBulkPublishRequest + @see AWSCognitoSyncBulkPublishResponse + */ +- (void)bulkPublish:(AWSCognitoSyncBulkPublishRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncBulkPublishResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Deletes the specific dataset. The dataset will be deleted permanently, and the action can't be undone. Datasets that this dataset was merged with will no longer report the merge. Any subsequent operation on this dataset will result in a ResourceNotFoundException.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the DeleteDataset service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncDeleteDatasetResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorResourceConflict`. + + @see AWSCognitoSyncDeleteDatasetRequest + @see AWSCognitoSyncDeleteDatasetResponse + */ +- (AWSTask *)deleteDataset:(AWSCognitoSyncDeleteDatasetRequest *)request; + +/** +

Deletes the specific dataset. The dataset will be deleted permanently, and the action can't be undone. Datasets that this dataset was merged with will no longer report the merge. Any subsequent operation on this dataset will result in a ResourceNotFoundException.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the DeleteDataset service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorResourceConflict`. + + @see AWSCognitoSyncDeleteDatasetRequest + @see AWSCognitoSyncDeleteDatasetResponse + */ +- (void)deleteDataset:(AWSCognitoSyncDeleteDatasetRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncDeleteDatasetResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets meta data about a dataset by identity and dataset name. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the DescribeDataset service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncDescribeDatasetResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeDatasetRequest + @see AWSCognitoSyncDescribeDatasetResponse + */ +- (AWSTask *)describeDataset:(AWSCognitoSyncDescribeDatasetRequest *)request; + +/** +

Gets meta data about a dataset by identity and dataset name. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the DescribeDataset service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeDatasetRequest + @see AWSCognitoSyncDescribeDatasetResponse + */ +- (void)describeDataset:(AWSCognitoSyncDescribeDatasetRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncDescribeDatasetResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets usage details (for example, data storage) about a particular identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityPoolUsage service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncDescribeIdentityPoolUsageResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeIdentityPoolUsageRequest + @see AWSCognitoSyncDescribeIdentityPoolUsageResponse + */ +- (AWSTask *)describeIdentityPoolUsage:(AWSCognitoSyncDescribeIdentityPoolUsageRequest *)request; + +/** +

Gets usage details (for example, data storage) about a particular identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityPoolUsage service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeIdentityPoolUsageRequest + @see AWSCognitoSyncDescribeIdentityPoolUsageResponse + */ +- (void)describeIdentityPoolUsage:(AWSCognitoSyncDescribeIdentityPoolUsageRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncDescribeIdentityPoolUsageResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets usage information for an identity, including number of datasets and data usage.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityUsage service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncDescribeIdentityUsageResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeIdentityUsageRequest + @see AWSCognitoSyncDescribeIdentityUsageResponse + */ +- (AWSTask *)describeIdentityUsage:(AWSCognitoSyncDescribeIdentityUsageRequest *)request; + +/** +

Gets usage information for an identity, including number of datasets and data usage.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityUsage service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncDescribeIdentityUsageRequest + @see AWSCognitoSyncDescribeIdentityUsageResponse + */ +- (void)describeIdentityUsage:(AWSCognitoSyncDescribeIdentityUsageRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncDescribeIdentityUsageResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Get the status of the last BulkPublish operation for an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetBulkPublishDetails service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncGetBulkPublishDetailsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncGetBulkPublishDetailsRequest + @see AWSCognitoSyncGetBulkPublishDetailsResponse + */ +- (AWSTask *)getBulkPublishDetails:(AWSCognitoSyncGetBulkPublishDetailsRequest *)request; + +/** +

Get the status of the last BulkPublish operation for an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetBulkPublishDetails service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncGetBulkPublishDetailsRequest + @see AWSCognitoSyncGetBulkPublishDetailsResponse + */ +- (void)getBulkPublishDetails:(AWSCognitoSyncGetBulkPublishDetailsRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncGetBulkPublishDetailsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets the events and the corresponding Lambda functions associated with an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetCognitoEvents service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncGetCognitoEventsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncGetCognitoEventsRequest + @see AWSCognitoSyncGetCognitoEventsResponse + */ +- (AWSTask *)getCognitoEvents:(AWSCognitoSyncGetCognitoEventsRequest *)request; + +/** +

Gets the events and the corresponding Lambda functions associated with an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetCognitoEvents service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncGetCognitoEventsRequest + @see AWSCognitoSyncGetCognitoEventsResponse + */ +- (void)getCognitoEvents:(AWSCognitoSyncGetCognitoEventsRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncGetCognitoEventsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets the configuration settings of an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetIdentityPoolConfiguration service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncGetIdentityPoolConfigurationResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncGetIdentityPoolConfigurationRequest + @see AWSCognitoSyncGetIdentityPoolConfigurationResponse + */ +- (AWSTask *)getIdentityPoolConfiguration:(AWSCognitoSyncGetIdentityPoolConfigurationRequest *)request; + +/** +

Gets the configuration settings of an identity pool.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the GetIdentityPoolConfiguration service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncGetIdentityPoolConfigurationRequest + @see AWSCognitoSyncGetIdentityPoolConfigurationResponse + */ +- (void)getIdentityPoolConfiguration:(AWSCognitoSyncGetIdentityPoolConfigurationRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncGetIdentityPoolConfigurationResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Lists datasets for an identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListDatasets can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use the Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the ListDatasets service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncListDatasetsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncListDatasetsRequest + @see AWSCognitoSyncListDatasetsResponse + */ +- (AWSTask *)listDatasets:(AWSCognitoSyncListDatasetsRequest *)request; + +/** +

Lists datasets for an identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListDatasets can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use the Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the ListDatasets service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncListDatasetsRequest + @see AWSCognitoSyncListDatasetsResponse + */ +- (void)listDatasets:(AWSCognitoSyncListDatasetsRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncListDatasetsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets a list of identity pools registered with Cognito.

ListIdentityPoolUsage can only be called with developer credentials. You cannot make this API call with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the ListIdentityPoolUsage service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncListIdentityPoolUsageResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncListIdentityPoolUsageRequest + @see AWSCognitoSyncListIdentityPoolUsageResponse + */ +- (AWSTask *)listIdentityPoolUsage:(AWSCognitoSyncListIdentityPoolUsageRequest *)request; + +/** +

Gets a list of identity pools registered with Cognito.

ListIdentityPoolUsage can only be called with developer credentials. You cannot make this API call with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the ListIdentityPoolUsage service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncListIdentityPoolUsageRequest + @see AWSCognitoSyncListIdentityPoolUsageResponse + */ +- (void)listIdentityPoolUsage:(AWSCognitoSyncListIdentityPoolUsageRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncListIdentityPoolUsageResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets paginated records, optionally changed after a particular sync count for a dataset and identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListRecords can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the ListRecords service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncListRecordsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncListRecordsRequest + @see AWSCognitoSyncListRecordsResponse + */ +- (AWSTask *)listRecords:(AWSCognitoSyncListRecordsRequest *)request; + +/** +

Gets paginated records, optionally changed after a particular sync count for a dataset and identity. With Amazon Cognito Sync, each identity has access only to its own data. Thus, the credentials used to make this API call need to have access to the identity data.

ListRecords can be called with temporary user credentials provided by Cognito Identity or with developer credentials. You should use Cognito Identity credentials to make this API call.

+ + @param request A container for the necessary parameters to execute the ListRecords service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncListRecordsRequest + @see AWSCognitoSyncListRecordsResponse + */ +- (void)listRecords:(AWSCognitoSyncListRecordsRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncListRecordsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Registers a device to receive push sync notifications.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the RegisterDevice service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncRegisterDeviceResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncRegisterDeviceRequest + @see AWSCognitoSyncRegisterDeviceResponse + */ +- (AWSTask *)registerDevice:(AWSCognitoSyncRegisterDeviceRequest *)request; + +/** +

Registers a device to receive push sync notifications.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the RegisterDevice service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncRegisterDeviceRequest + @see AWSCognitoSyncRegisterDeviceResponse + */ +- (void)registerDevice:(AWSCognitoSyncRegisterDeviceRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncRegisterDeviceResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Sets the AWS Lambda function for a given event type for an identity pool. This request only updates the key/value pair specified. Other key/values pairs are not updated. To remove a key value pair, pass a empty value for the particular key.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the SetCognitoEvents service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will be `nil`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncSetCognitoEventsRequest + */ +- (AWSTask *)setCognitoEvents:(AWSCognitoSyncSetCognitoEventsRequest *)request; + +/** +

Sets the AWS Lambda function for a given event type for an identity pool. This request only updates the key/value pair specified. Other key/values pairs are not updated. To remove a key value pair, pass a empty value for the particular key.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the SetCognitoEvents service method. + @param completionHandler The completion handler to call when the load request is complete. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncSetCognitoEventsRequest + */ +- (void)setCognitoEvents:(AWSCognitoSyncSetCognitoEventsRequest *)request completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler; + +/** +

Sets the necessary configuration for push sync.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the SetIdentityPoolConfiguration service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncSetIdentityPoolConfigurationResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorConcurrentModification`. + + @see AWSCognitoSyncSetIdentityPoolConfigurationRequest + @see AWSCognitoSyncSetIdentityPoolConfigurationResponse + */ +- (AWSTask *)setIdentityPoolConfiguration:(AWSCognitoSyncSetIdentityPoolConfigurationRequest *)request; + +/** +

Sets the necessary configuration for push sync.

This API can only be called with developer credentials. You cannot call this API with the temporary user credentials provided by Cognito Identity.

+ + @param request A container for the necessary parameters to execute the SetIdentityPoolConfiguration service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorConcurrentModification`. + + @see AWSCognitoSyncSetIdentityPoolConfigurationRequest + @see AWSCognitoSyncSetIdentityPoolConfigurationResponse + */ +- (void)setIdentityPoolConfiguration:(AWSCognitoSyncSetIdentityPoolConfigurationRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncSetIdentityPoolConfigurationResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Subscribes to receive notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the SubscribeToDataset service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncSubscribeToDatasetResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncSubscribeToDatasetRequest + @see AWSCognitoSyncSubscribeToDatasetResponse + */ +- (AWSTask *)subscribeToDataset:(AWSCognitoSyncSubscribeToDatasetRequest *)request; + +/** +

Subscribes to receive notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the SubscribeToDataset service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncSubscribeToDatasetRequest + @see AWSCognitoSyncSubscribeToDatasetResponse + */ +- (void)subscribeToDataset:(AWSCognitoSyncSubscribeToDatasetRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncSubscribeToDatasetResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Unsubscribes from receiving notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the UnsubscribeFromDataset service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncUnsubscribeFromDatasetResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncUnsubscribeFromDatasetRequest + @see AWSCognitoSyncUnsubscribeFromDatasetResponse + */ +- (AWSTask *)unsubscribeFromDataset:(AWSCognitoSyncUnsubscribeFromDatasetRequest *)request; + +/** +

Unsubscribes from receiving notifications when a dataset is modified by another device.

This API can only be called with temporary credentials provided by Cognito Identity. You cannot call this API with developer credentials.

+ + @param request A container for the necessary parameters to execute the UnsubscribeFromDataset service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorInternalError`, `AWSCognitoSyncErrorInvalidConfiguration`, `AWSCognitoSyncErrorTooManyRequests`. + + @see AWSCognitoSyncUnsubscribeFromDatasetRequest + @see AWSCognitoSyncUnsubscribeFromDatasetResponse + */ +- (void)unsubscribeFromDataset:(AWSCognitoSyncUnsubscribeFromDatasetRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncUnsubscribeFromDatasetResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Posts updates to records and adds and deletes records for a dataset and user.

The sync count in the record patch is your last known sync count for that record. The server will reject an UpdateRecords request with a ResourceConflictException if you try to patch a record with a new value but a stale sync count.

For example, if the sync count on the server is 5 for a key called highScore and you try and submit a new highScore with sync count of 4, the request will be rejected. To obtain the current sync count for a record, call ListRecords. On a successful update of the record, the response returns the new sync count for that record. You should present that sync count the next time you try to update that same record. When the record does not exist, specify the sync count as 0.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the UpdateRecords service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoSyncUpdateRecordsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorLimitExceeded`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorResourceConflict`, `AWSCognitoSyncErrorInvalidLambdaFunctionOutput`, `AWSCognitoSyncErrorLambdaThrottled`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncUpdateRecordsRequest + @see AWSCognitoSyncUpdateRecordsResponse + */ +- (AWSTask *)updateRecords:(AWSCognitoSyncUpdateRecordsRequest *)request; + +/** +

Posts updates to records and adds and deletes records for a dataset and user.

The sync count in the record patch is your last known sync count for that record. The server will reject an UpdateRecords request with a ResourceConflictException if you try to patch a record with a new value but a stale sync count.

For example, if the sync count on the server is 5 for a key called highScore and you try and submit a new highScore with sync count of 4, the request will be rejected. To obtain the current sync count for a record, call ListRecords. On a successful update of the record, the response returns the new sync count for that record. You should present that sync count the next time you try to update that same record. When the record does not exist, specify the sync count as 0.

This API can be called with temporary user credentials provided by Cognito Identity or with developer credentials.

+ + @param request A container for the necessary parameters to execute the UpdateRecords service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoSyncErrorDomain` domain and the following error code: `AWSCognitoSyncErrorInvalidParameter`, `AWSCognitoSyncErrorLimitExceeded`, `AWSCognitoSyncErrorNotAuthorized`, `AWSCognitoSyncErrorResourceNotFound`, `AWSCognitoSyncErrorResourceConflict`, `AWSCognitoSyncErrorInvalidLambdaFunctionOutput`, `AWSCognitoSyncErrorLambdaThrottled`, `AWSCognitoSyncErrorTooManyRequests`, `AWSCognitoSyncErrorInternalError`. + + @see AWSCognitoSyncUpdateRecordsRequest + @see AWSCognitoSyncUpdateRecordsResponse + */ +- (void)updateRecords:(AWSCognitoSyncUpdateRecordsRequest *)request completionHandler:(void (^ _Nullable)(AWSCognitoSyncUpdateRecordsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.m b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.m new file mode 100644 index 00000000..b70c4dec --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/CognitoSync/AWSCognitoSyncService.m @@ -0,0 +1,674 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoSyncService.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import "AWSCognitoSyncResources.h" + +static NSString *const AWSInfoCognitoSync = @"CognitoSync"; +static NSString *const AWSCognitoSyncSDKVersion = @"2.5.6"; + + +@interface AWSCognitoSyncResponseSerializer : AWSJSONResponseSerializer + +@end + +@implementation AWSCognitoSyncResponseSerializer + +#pragma mark - Service errors + +static NSDictionary *errorCodeDictionary = nil; ++ (void)initialize { + errorCodeDictionary = @{ + @"AlreadyStreamedException" : @(AWSCognitoSyncErrorAlreadyStreamed), + @"ConcurrentModificationException" : @(AWSCognitoSyncErrorConcurrentModification), + @"DuplicateRequestException" : @(AWSCognitoSyncErrorDuplicateRequest), + @"InternalErrorException" : @(AWSCognitoSyncErrorInternalError), + @"InvalidConfigurationException" : @(AWSCognitoSyncErrorInvalidConfiguration), + @"InvalidLambdaFunctionOutputException" : @(AWSCognitoSyncErrorInvalidLambdaFunctionOutput), + @"InvalidParameterException" : @(AWSCognitoSyncErrorInvalidParameter), + @"LambdaThrottledException" : @(AWSCognitoSyncErrorLambdaThrottled), + @"LimitExceededException" : @(AWSCognitoSyncErrorLimitExceeded), + @"NotAuthorizedException" : @(AWSCognitoSyncErrorNotAuthorized), + @"ResourceConflictException" : @(AWSCognitoSyncErrorResourceConflict), + @"ResourceNotFoundException" : @(AWSCognitoSyncErrorResourceNotFound), + @"TooManyRequestsException" : @(AWSCognitoSyncErrorTooManyRequests), + }; +} + +#pragma mark - + +- (id)responseObjectForResponse:(NSHTTPURLResponse *)response + originalRequest:(NSURLRequest *)originalRequest + currentRequest:(NSURLRequest *)currentRequest + data:(id)data + error:(NSError *__autoreleasing *)error { + id responseObject = [super responseObjectForResponse:response + originalRequest:originalRequest + currentRequest:currentRequest + data:data + error:error]; + if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { + NSString *errorTypeString = [[response allHeaderFields] objectForKey:@"x-amzn-ErrorType"]; + NSString *errorTypeHeader = [[errorTypeString componentsSeparatedByString:@":"] firstObject]; + + if ([errorTypeString length] > 0 && errorTypeHeader) { + if (errorCodeDictionary[errorTypeHeader]) { + if (error) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : [responseObject objectForKey:@"message"]?[responseObject objectForKey:@"message"]:[NSNull null], NSLocalizedFailureReasonErrorKey: errorTypeString}; + *error = [NSError errorWithDomain:AWSCognitoSyncErrorDomain + code:[[errorCodeDictionary objectForKey:errorTypeHeader] integerValue] + userInfo:userInfo]; + } + return responseObject; + } else if (errorTypeHeader) { + if (error) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey : [responseObject objectForKey:@"message"]?[responseObject objectForKey:@"message"]:[NSNull null], NSLocalizedFailureReasonErrorKey: errorTypeString}; + *error = [NSError errorWithDomain:AWSCognitoSyncErrorDomain + code:AWSCognitoSyncErrorUnknown + userInfo:userInfo]; + } + return responseObject; + } + } + } + + if (!*error && response.statusCode/100 != 2) { + *error = [NSError errorWithDomain:AWSCognitoSyncErrorDomain + code:AWSCognitoSyncErrorUnknown + userInfo:nil]; + } + + if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { + if (self.outputClass) { + responseObject = [AWSMTLJSONAdapter modelOfClass:self.outputClass + fromJSONDictionary:responseObject + error:error]; + } + } + return responseObject; +} + +@end + +@interface AWSCognitoSyncRequestRetryHandler : AWSURLRequestRetryHandler + +@end + +@implementation AWSCognitoSyncRequestRetryHandler + +@end + +@interface AWSRequest() + +@property (nonatomic, strong) AWSNetworkingRequest *internalRequest; + +@end + +@interface AWSCognitoSync() + +@property (nonatomic, strong) AWSNetworking *networking; +@property (nonatomic, strong) AWSServiceConfiguration *configuration; + +@end + +@interface AWSServiceConfiguration() + +@property (nonatomic, strong) AWSEndpoint *endpoint; + +@end + +@interface AWSEndpoint() + +- (void) setRegion:(AWSRegionType)regionType service:(AWSServiceType)serviceType; + +@end + +@implementation AWSCognitoSync + + +#pragma mark - Setup + +static AWSSynchronizedMutableDictionary *_serviceClients = nil; + ++ (instancetype)defaultCognitoSync { + static AWSCognitoSync *_defaultCognitoSync = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AWSServiceConfiguration *serviceConfiguration = nil; + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoCognitoSync]; + if (serviceInfo) { + serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + } + + if (!serviceConfiguration) { + serviceConfiguration = [AWSServiceManager defaultServiceManager].defaultServiceConfiguration; + } + + if (!serviceConfiguration) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method." + userInfo:nil]; + } + _defaultCognitoSync = [[AWSCognitoSync alloc] initWithConfiguration:serviceConfiguration]; + }); + + return _defaultCognitoSync; +} + ++ (void)registerCognitoSyncWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _serviceClients = [AWSSynchronizedMutableDictionary new]; + }); + [_serviceClients setObject:[[AWSCognitoSync alloc] initWithConfiguration:configuration] + forKey:key]; +} + ++ (instancetype)CognitoSyncForKey:(NSString *)key { + @synchronized(self) { + AWSCognitoSync *serviceClient = [_serviceClients objectForKey:key]; + if (serviceClient) { + return serviceClient; + } + + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoCognitoSync + forKey:key]; + if (serviceInfo) { + AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + [AWSCognitoSync registerCognitoSyncWithConfiguration:serviceConfiguration + forKey:key]; + } + + return [_serviceClients objectForKey:key]; + } +} + ++ (void)removeCognitoSyncForKey:(NSString *)key { + [_serviceClients removeObjectForKey:key]; +} + +- (instancetype)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"`- init` is not a valid initializer. Use `+ defaultCognitoSync` or `+ CognitoSyncForKey:` instead." + userInfo:nil]; + return nil; +} + +#pragma mark - + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration { + if (self = [super init]) { + _configuration = [configuration copy]; + + if(!configuration.endpoint){ + _configuration.endpoint = [[AWSEndpoint alloc] initWithRegion:_configuration.regionType + service:AWSServiceCognitoSync + useUnsafeURL:NO]; + }else{ + [_configuration.endpoint setRegion:_configuration.regionType + service:AWSServiceCognitoSync]; + } + + AWSSignatureV4Signer *signer = [[AWSSignatureV4Signer alloc] initWithCredentialsProvider:_configuration.credentialsProvider + endpoint:_configuration.endpoint]; + AWSNetworkingRequestInterceptor *baseInterceptor = [[AWSNetworkingRequestInterceptor alloc] initWithUserAgent:_configuration.userAgent]; + _configuration.requestInterceptors = @[baseInterceptor, signer]; + + _configuration.baseURL = _configuration.endpoint.URL; + _configuration.retryHandler = [[AWSCognitoSyncRequestRetryHandler alloc] initWithMaximumRetryCount:_configuration.maxRetryCount]; + _configuration.headers = @{@"Content-Type" : @"application/x-amz-json-1.1"}; + + _networking = [[AWSNetworking alloc] initWithConfiguration:_configuration]; + } + + return self; +} + +- (AWSTask *)invokeRequest:(AWSRequest *)request + HTTPMethod:(AWSHTTPMethod)HTTPMethod + URLString:(NSString *) URLString + targetPrefix:(NSString *)targetPrefix + operationName:(NSString *)operationName + outputClass:(Class)outputClass { + + @autoreleasepool { + if (!request) { + request = [AWSRequest new]; + } + + AWSNetworkingRequest *networkingRequest = request.internalRequest; + if (request) { + networkingRequest.parameters = [[AWSMTLJSONAdapter JSONDictionaryFromModel:request] aws_removeNullValues]; + } else { + networkingRequest.parameters = @{}; + } + + networkingRequest.HTTPMethod = HTTPMethod; + networkingRequest.requestSerializer = [[AWSJSONRequestSerializer alloc] initWithJSONDefinition:[[AWSCognitoSyncResources sharedInstance] JSONObject] + actionName:operationName]; + networkingRequest.responseSerializer = [[AWSCognitoSyncResponseSerializer alloc] initWithJSONDefinition:[[AWSCognitoSyncResources sharedInstance] JSONObject] + actionName:operationName + outputClass:outputClass]; + + return [self.networking sendRequest:networkingRequest]; + } +} + +#pragma mark - Service method + +- (AWSTask *)bulkPublish:(AWSCognitoSyncBulkPublishRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/bulkpublish" + targetPrefix:@"" + operationName:@"BulkPublish" + outputClass:[AWSCognitoSyncBulkPublishResponse class]]; +} + +- (void)bulkPublish:(AWSCognitoSyncBulkPublishRequest *)request + completionHandler:(void (^)(AWSCognitoSyncBulkPublishResponse *response, NSError *error))completionHandler { + [[self bulkPublish:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncBulkPublishResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)deleteDataset:(AWSCognitoSyncDeleteDatasetRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodDELETE + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}" + targetPrefix:@"" + operationName:@"DeleteDataset" + outputClass:[AWSCognitoSyncDeleteDatasetResponse class]]; +} + +- (void)deleteDataset:(AWSCognitoSyncDeleteDatasetRequest *)request + completionHandler:(void (^)(AWSCognitoSyncDeleteDatasetResponse *response, NSError *error))completionHandler { + [[self deleteDataset:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncDeleteDatasetResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)describeDataset:(AWSCognitoSyncDescribeDatasetRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}" + targetPrefix:@"" + operationName:@"DescribeDataset" + outputClass:[AWSCognitoSyncDescribeDatasetResponse class]]; +} + +- (void)describeDataset:(AWSCognitoSyncDescribeDatasetRequest *)request + completionHandler:(void (^)(AWSCognitoSyncDescribeDatasetResponse *response, NSError *error))completionHandler { + [[self describeDataset:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncDescribeDatasetResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)describeIdentityPoolUsage:(AWSCognitoSyncDescribeIdentityPoolUsageRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}" + targetPrefix:@"" + operationName:@"DescribeIdentityPoolUsage" + outputClass:[AWSCognitoSyncDescribeIdentityPoolUsageResponse class]]; +} + +- (void)describeIdentityPoolUsage:(AWSCognitoSyncDescribeIdentityPoolUsageRequest *)request + completionHandler:(void (^)(AWSCognitoSyncDescribeIdentityPoolUsageResponse *response, NSError *error))completionHandler { + [[self describeIdentityPoolUsage:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncDescribeIdentityPoolUsageResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)describeIdentityUsage:(AWSCognitoSyncDescribeIdentityUsageRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}" + targetPrefix:@"" + operationName:@"DescribeIdentityUsage" + outputClass:[AWSCognitoSyncDescribeIdentityUsageResponse class]]; +} + +- (void)describeIdentityUsage:(AWSCognitoSyncDescribeIdentityUsageRequest *)request + completionHandler:(void (^)(AWSCognitoSyncDescribeIdentityUsageResponse *response, NSError *error))completionHandler { + [[self describeIdentityUsage:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncDescribeIdentityUsageResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getBulkPublishDetails:(AWSCognitoSyncGetBulkPublishDetailsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/getBulkPublishDetails" + targetPrefix:@"" + operationName:@"GetBulkPublishDetails" + outputClass:[AWSCognitoSyncGetBulkPublishDetailsResponse class]]; +} + +- (void)getBulkPublishDetails:(AWSCognitoSyncGetBulkPublishDetailsRequest *)request + completionHandler:(void (^)(AWSCognitoSyncGetBulkPublishDetailsResponse *response, NSError *error))completionHandler { + [[self getBulkPublishDetails:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncGetBulkPublishDetailsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getCognitoEvents:(AWSCognitoSyncGetCognitoEventsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/events" + targetPrefix:@"" + operationName:@"GetCognitoEvents" + outputClass:[AWSCognitoSyncGetCognitoEventsResponse class]]; +} + +- (void)getCognitoEvents:(AWSCognitoSyncGetCognitoEventsRequest *)request + completionHandler:(void (^)(AWSCognitoSyncGetCognitoEventsResponse *response, NSError *error))completionHandler { + [[self getCognitoEvents:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncGetCognitoEventsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getIdentityPoolConfiguration:(AWSCognitoSyncGetIdentityPoolConfigurationRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/configuration" + targetPrefix:@"" + operationName:@"GetIdentityPoolConfiguration" + outputClass:[AWSCognitoSyncGetIdentityPoolConfigurationResponse class]]; +} + +- (void)getIdentityPoolConfiguration:(AWSCognitoSyncGetIdentityPoolConfigurationRequest *)request + completionHandler:(void (^)(AWSCognitoSyncGetIdentityPoolConfigurationResponse *response, NSError *error))completionHandler { + [[self getIdentityPoolConfiguration:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncGetIdentityPoolConfigurationResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)listDatasets:(AWSCognitoSyncListDatasetsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets" + targetPrefix:@"" + operationName:@"ListDatasets" + outputClass:[AWSCognitoSyncListDatasetsResponse class]]; +} + +- (void)listDatasets:(AWSCognitoSyncListDatasetsRequest *)request + completionHandler:(void (^)(AWSCognitoSyncListDatasetsResponse *response, NSError *error))completionHandler { + [[self listDatasets:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncListDatasetsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)listIdentityPoolUsage:(AWSCognitoSyncListIdentityPoolUsageRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools" + targetPrefix:@"" + operationName:@"ListIdentityPoolUsage" + outputClass:[AWSCognitoSyncListIdentityPoolUsageResponse class]]; +} + +- (void)listIdentityPoolUsage:(AWSCognitoSyncListIdentityPoolUsageRequest *)request + completionHandler:(void (^)(AWSCognitoSyncListIdentityPoolUsageResponse *response, NSError *error))completionHandler { + [[self listIdentityPoolUsage:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncListIdentityPoolUsageResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)listRecords:(AWSCognitoSyncListRecordsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodGET + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/records" + targetPrefix:@"" + operationName:@"ListRecords" + outputClass:[AWSCognitoSyncListRecordsResponse class]]; +} + +- (void)listRecords:(AWSCognitoSyncListRecordsRequest *)request + completionHandler:(void (^)(AWSCognitoSyncListRecordsResponse *response, NSError *error))completionHandler { + [[self listRecords:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncListRecordsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)registerDevice:(AWSCognitoSyncRegisterDeviceRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/identity/{IdentityId}/device" + targetPrefix:@"" + operationName:@"RegisterDevice" + outputClass:[AWSCognitoSyncRegisterDeviceResponse class]]; +} + +- (void)registerDevice:(AWSCognitoSyncRegisterDeviceRequest *)request + completionHandler:(void (^)(AWSCognitoSyncRegisterDeviceResponse *response, NSError *error))completionHandler { + [[self registerDevice:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncRegisterDeviceResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)setCognitoEvents:(AWSCognitoSyncSetCognitoEventsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/events" + targetPrefix:@"" + operationName:@"SetCognitoEvents" + outputClass:nil]; +} + +- (void)setCognitoEvents:(AWSCognitoSyncSetCognitoEventsRequest *)request + completionHandler:(void (^)(NSError *error))completionHandler { + [[self setCognitoEvents:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSError *error = task.error; + + if (completionHandler) { + completionHandler(error); + } + + return nil; + }]; +} + +- (AWSTask *)setIdentityPoolConfiguration:(AWSCognitoSyncSetIdentityPoolConfigurationRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/configuration" + targetPrefix:@"" + operationName:@"SetIdentityPoolConfiguration" + outputClass:[AWSCognitoSyncSetIdentityPoolConfigurationResponse class]]; +} + +- (void)setIdentityPoolConfiguration:(AWSCognitoSyncSetIdentityPoolConfigurationRequest *)request + completionHandler:(void (^)(AWSCognitoSyncSetIdentityPoolConfigurationResponse *response, NSError *error))completionHandler { + [[self setIdentityPoolConfiguration:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncSetIdentityPoolConfigurationResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)subscribeToDataset:(AWSCognitoSyncSubscribeToDatasetRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/subscriptions/{DeviceId}" + targetPrefix:@"" + operationName:@"SubscribeToDataset" + outputClass:[AWSCognitoSyncSubscribeToDatasetResponse class]]; +} + +- (void)subscribeToDataset:(AWSCognitoSyncSubscribeToDatasetRequest *)request + completionHandler:(void (^)(AWSCognitoSyncSubscribeToDatasetResponse *response, NSError *error))completionHandler { + [[self subscribeToDataset:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncSubscribeToDatasetResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)unsubscribeFromDataset:(AWSCognitoSyncUnsubscribeFromDatasetRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodDELETE + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}/subscriptions/{DeviceId}" + targetPrefix:@"" + operationName:@"UnsubscribeFromDataset" + outputClass:[AWSCognitoSyncUnsubscribeFromDatasetResponse class]]; +} + +- (void)unsubscribeFromDataset:(AWSCognitoSyncUnsubscribeFromDatasetRequest *)request + completionHandler:(void (^)(AWSCognitoSyncUnsubscribeFromDatasetResponse *response, NSError *error))completionHandler { + [[self unsubscribeFromDataset:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncUnsubscribeFromDatasetResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)updateRecords:(AWSCognitoSyncUpdateRecordsRequest *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"/identitypools/{IdentityPoolId}/identities/{IdentityId}/datasets/{DatasetName}" + targetPrefix:@"" + operationName:@"UpdateRecords" + outputClass:[AWSCognitoSyncUpdateRecordsResponse class]]; +} + +- (void)updateRecords:(AWSCognitoSyncUpdateRecordsRequest *)request + completionHandler:(void (^)(AWSCognitoSyncUpdateRecordsResponse *response, NSError *error))completionHandler { + [[self updateRecords:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoSyncUpdateRecordsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +#pragma mark - + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConflict_Internal.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConflict_Internal.h new file mode 100644 index 00000000..5f395869 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConflict_Internal.h @@ -0,0 +1,33 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoConflict.h" + +@interface AWSCognitoRecordTuple () +-(instancetype) initWithLocalRecord:(AWSCognitoRecord *)local remoteRecord:(AWSCognitoRecord *)remote; +@end + +@interface AWSCognitoResolvedConflict() +@property (nonatomic, readonly) AWSCognitoRecord *resolvedConflict; +@property (nonatomic, readonly) AWSCognitoConflict *conflict; +- (instancetype) initWithRemoteRecord:(AWSCognitoConflict *)conflict; +- (instancetype) initWithLocalRecord:(AWSCognitoConflict *)conflict; +- (instancetype) initWithValue:(AWSCognitoConflict *)conflict newValue:(NSString *)value; ++ (instancetype) resolvedConflictWithRemoteRecord:(AWSCognitoConflict *)conflict; ++ (instancetype) resolvedConflictWithLocalRecord:(AWSCognitoConflict *)conflict; ++ (instancetype) resolvedConflictWithValue:(AWSCognitoConflict *)conflict newValue:(NSString *)value; +@end \ No newline at end of file diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.h new file mode 100644 index 00000000..b3703e4a --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.h @@ -0,0 +1,68 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +FOUNDATION_EXPORT NSString *const AWSCognitoDefaultSqliteDataTableName; +FOUNDATION_EXPORT NSString *const AWSCognitoTableIdentityKeyName; +FOUNDATION_EXPORT NSString *const AWSCognitoTableDatasetKeyName; +FOUNDATION_EXPORT NSString *const AWSCognitoTableRecordKeyName; +FOUNDATION_EXPORT NSString *const AWSCognitoUnknownIdentity; +FOUNDATION_EXPORT NSString *const AWSCognitoRecordValueName; +FOUNDATION_EXPORT NSString *const AWSCognitoDataFieldKeyName; +FOUNDATION_EXPORT NSString *const AWSCognitoTypeFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoLastModifiedFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoModifiedByFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoRecordCountFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoDataStorageFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoDatasetCreationDateFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoDirtyFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoSyncCountFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoDefaultSqliteMetadataTableName; +FOUNDATION_EXPORT NSString *const AWSCognitoDatasetFieldName; +FOUNDATION_EXPORT NSString *const AWSCognitoLastSyncCount; + +FOUNDATION_EXPORT NSString* const AWSCognitoDeletedRecord; +FOUNDATION_EXPORT int64_t const AWSCognitoNotSyncedDeletedRecordDirty; +FOUNDATION_EXPORT NSString *const AWSCognitoUserDefaultsUserAgentPrefix; + +FOUNDATION_EXPORT uint32_t const AWSCognitoMaxSyncRetries; +FOUNDATION_EXPORT BOOL const AWSCognitoSynchronizeOnWiFiOnly; + +FOUNDATION_EXPORT uint32_t const AWSCognitoMaxDatasetSize; +FOUNDATION_EXPORT uint32_t const AWSCognitoMinKeySize; +FOUNDATION_EXPORT uint32_t const AWSCognitoMaxKeySize; +FOUNDATION_EXPORT uint32_t const AWSCognitoMaxRecordValueSize; +FOUNDATION_EXPORT uint32_t const AWSCognitoMaxNumRecords; + +FOUNDATION_EXPORT NSString *const AWSCognitoSyncPushApns; +FOUNDATION_EXPORT NSString *const AWSCognitoSyncPushApnsSandbox; + +#pragma mark - Standard error messages + +FOUNDATION_EXPORT NSString *const AWSCognitoErrorRemoteDataStorageFailedDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorRemoteDataStorageFailedRecoverySuggestion; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorInvalidDataValueDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorInvalidDataValueRecoverySuggestion; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorUserDataSizeLimitExceededDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorUserDataSizeLimitExceededRecoverySuggestion; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorLocalDataStorageFailedDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorLocalDataStorageFailedRecoverySuggestion; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorIllegalArgumentDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorIllegalArgumentRecoverySuggestion; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorUnknownDataTypeDescription; +FOUNDATION_EXPORT NSString *const AWSCognitoErrorUnknownDataTypeRecoverySuggestion; diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.m b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.m new file mode 100644 index 00000000..9ae42f86 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoConstants.m @@ -0,0 +1,70 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoConstants.h" + +NSString *const AWSCognitoDefaultSqliteDataTableName = @"CognitoData"; +NSString *const AWSCognitoTableDatasetKeyName = @"Dataset"; +NSString *const AWSCognitoTableIdentityKeyName = @"IdentityId"; +NSString *const AWSCognitoUnknownIdentity = @"UnknownId"; +NSString *const AWSCognitoTableRecordKeyName = @"Key"; +NSString *const AWSCognitoRecordValueName = @"Data"; +NSString *const AWSCognitoDataFieldKeyName = @"v"; +NSString *const AWSCognitoTypeFieldName = @"Type"; +NSString *const AWSCognitoLastModifiedFieldName = @"LastModified"; +NSString *const AWSCognitoModifiedByFieldName = @"ModifiedBy"; +NSString *const AWSCognitoRecordCountFieldName = @"RecordCount"; +NSString *const AWSCognitoDataStorageFieldName = @"DataStorage"; +NSString *const AWSCognitoDatasetCreationDateFieldName = @"CreationDate"; +NSString *const AWSCognitoDirtyFieldName = @"Dirty"; +NSString *const AWSCognitoDatasetFieldName = @"Dataset"; +NSString *const AWSCognitoSyncCountFieldName = @"SyncCount"; +NSString *const AWSCognitoDefaultSqliteMetadataTableName = @"CognitoMetadata"; +NSString *const AWSCognitoLastSyncCount = @"LastSyncCount"; +int64_t const AWSCognitoNotSyncedDeletedRecordDirty = -1; +NSString* const AWSCognitoDeletedRecord = @"\0"; +NSString *const AWSCognitoUserDefaultsUserAgentPrefix = @"CognitoV1.0"; + +NSString *const AWSCognitoSyncPushApns = @"APNS"; +NSString *const AWSCognitoSyncPushApnsSandbox = @"APNS_SANDBOX"; + +uint32_t const AWSCognitoMaxSyncRetries = 5; +BOOL const AWSCognitoSynchronizeOnWiFiOnly = NO; + +uint32_t const AWSCognitoMaxDatasetSize = 1024*1024; +uint32_t const AWSCognitoMinKeySize = 1; +uint32_t const AWSCognitoMaxKeySize = 128; +uint32_t const AWSCognitoMaxRecordValueSize = AWSCognitoMaxDatasetSize-1; +uint32_t const AWSCognitoMaxNumRecords = 1024; + + +#pragma mark - Standard error messages + +NSString *const AWSCognitoErrorRemoteDataStorageFailedDescription = @"The Amazon Cognito call failed."; +NSString *const AWSCognitoErrorRemoteDataStorageFailedRecoverySuggestion = @"Try again later."; +NSString *const AWSCognitoErrorInvalidDataValueDescription = @"The Amazon Cognito call failed. The value for the key is invalid and has been deleted from the local database."; +NSString *const AWSCognitoErrorInvalidDataValueRecoverySuggestion = @"Investigate userInfo to retrieve the key and value of the failed request."; +NSString *const AWSCognitoErrorUserDataSizeLimitExceededDescription = @"The Amazon Cognito call failed. An item collection is too large. For each dataset, the total sizes of keys and values cannot exceed 1 MB."; +NSString *const AWSCognitoErrorUserDataSizeLimitExceededRecoverySuggestion = @"Fatal error."; +NSString *const AWSCognitoErrorLocalDataStorageFailedDescription = @"The SQLite call failed."; +NSString *const AWSCognitoErrorLocalDataStorageFailedRecoverySuggestion = @"Make sure you have enough disk space and the SQLite database file path is accessible."; +NSString *const AWSCognitoErrorIllegalArgumentDescription = @"The input value is invalid."; +NSString *const AWSCognitoErrorIllegalArgumentRecoverySuggestion = @"Make sure the input value is valid and try again."; +NSString *const AWSCognitoErrorUnknownDataTypeDescription = @"The data type is not recognized by this library version."; +NSString *const AWSCognitoErrorUnknownDataTypeRecoverySuggestion = @"Request the user upgrades to the latest version of your app."; +NSString *const AWSCognitoDeviceNotOnWifiNetworkDescription = @"The WiFi network is unreachable at this time."; +NSString *const AWSCognitoDeviceNotOnWifiNetworkRecoverySuggestion = @"Request the user connects to a WiFi network."; diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoDataset_Internal.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoDataset_Internal.h new file mode 100644 index 00000000..91b6fff4 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoDataset_Internal.h @@ -0,0 +1,43 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoDataset.h" + +@class AWSCognitoSync; + +@interface AWSCognitoDatasetMetadata() + +@property (nonatomic, strong) NSString *name; +@property (nonatomic, strong) NSNumber *lastSyncCount; +@property (nonatomic, strong) NSDate *creationDate; +@property (nonatomic, strong) NSNumber *dataStorage; +@property (nonatomic, strong) NSString *lastModifiedBy; +@property (nonatomic, strong) NSDate *lastModifiedDate; +@property (nonatomic, strong) NSNumber *numRecords; + +@end + +@interface AWSCognitoDataset() + +/** + * Use AWSCognitoClient.openOrCreateDataset to get a dataset. + */ +- (instancetype)initWithDatasetName:(NSString *)datasetName + sqliteManager:(AWSCognitoSQLiteManager *)sqliteManager + cognitoService:(AWSCognitoSync *)cognitoService; + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoRecord_Internal.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoRecord_Internal.h new file mode 100644 index 00000000..9aa0dc88 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoRecord_Internal.h @@ -0,0 +1,57 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoRecord.h" + +@interface AWSCognitoRecordMetadata() + +@property (nonatomic, strong) NSDate *lastModified; + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +@end + +@interface AWSCognitoRecord() + +/** + * Initializes a AWSCognitoRecord with the values from a dictionary. + * + * @param dictionary The dictionary must contain a mapping of NSStrings to NSStrings. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +/** + * Returns a copy of the AWSCognitoRecord with the last written time updated to the current time and the version number set based on the dirty count. + * + */ +- (AWSCognitoRecord *)copyForFlush; + +@end + +@interface AWSCognitoRecordValue() + +@property (nonatomic, assign) AWSCognitoRecordValueType type; +@property (nonatomic, strong) NSObject *stringValue; + + +- (instancetype)initWithString:(NSString *)value + type:(AWSCognitoRecordValueType)type; + +- (NSString *)toJsonString; +- (instancetype)initWithJson:(NSString *)json + type:(AWSCognitoRecordValueType)type; +@end \ No newline at end of file diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.h new file mode 100644 index 00000000..3dd3fc0b --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.h @@ -0,0 +1,59 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class AWSCognitoRecord; +@class AWSCognitoDatasetMetadata; + +@interface AWSCognitoSQLiteManager : NSObject + +@property (nonatomic, strong) NSString *identityId; +@property (nonatomic, strong) NSString *deviceId; + + +- (instancetype)initWithIdentityId:(NSString *)identityId deviceId:(NSString *)deviceId; +- (void)initializeDatasetTables:(NSString *) datasetName; +- (void)deleteAllData; +- (void)deleteSQLiteDatabase; + +- (NSArray *)getDatasets:(NSError **)error; +- (void)loadDatasetMetadata:(AWSCognitoDatasetMetadata *)dataset error:(NSError **)error; +- (BOOL)putDatasetMetadata:(NSArray *)datasets error:(NSError **)error; +- (BOOL)updateDatasetMetadata:(AWSCognitoDatasetMetadata *)dataset error:(NSError **)error; +- (AWSCognitoRecord *)getRecordById:(NSString *)recordId datasetName:(NSString *)datasetName error:(NSError **)error; +- (BOOL)putRecord:(AWSCognitoRecord *)record datasetName:(NSString *)datasetName error:(NSError **)error; +- (BOOL)flagRecordAsDeletedById:(NSString *)recordId datasetName:(NSString *)datasetName error:(NSError **)error; +- (BOOL)deleteRecordById:(NSString *)recordId datasetName:(NSString *)datasetName error:(NSError **)error; +- (BOOL)deleteDataset:(NSString *)datasetName error:(NSError **)error; +- (BOOL)deleteMetadata:(NSString *)datasetName error:(NSError **)error; +- (BOOL)updateWithRemoteChanges:(NSString *)datasetName nonConflicts:(NSArray *)nonConflictRecords resolvedConflicts:(NSArray *)resolvedConflicts error:(NSError **)error; +- (BOOL)updateLocalRecordMetadata:(NSString *)datasetName records:(NSArray *)updatedRecords error:(NSError **)error; +- (BOOL)resetSyncCount:(NSString *)datasetName error:(NSError **)error; + +- (NSNumber *) numRecords:(NSString *)datasetName; + +- (NSArray *)getMergeDatasets:(NSString *)datasetName error:(NSError **)error; +- (BOOL)reparentDatasets:(NSString *)oldId withNewId:(NSString *)newId error:(NSError **)error; + +- (NSArray *)allRecords:(NSString *)datasetName; +- (NSDictionary *)recordsUpdatedAfterLastSync:(NSString *)datasetName error:(NSError **)error; + +- (NSNumber *)lastSyncCount:(NSString *)datasetName; +- (void)updateLastSyncCount:(NSString *)datasetName syncCount:(NSNumber *)syncCount lastModifiedBy:(NSString *)lastModifiedBy; + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.m b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.m new file mode 100644 index 00000000..a47a78f5 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoSQLiteManager.m @@ -0,0 +1,1783 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + + +#import "AWSCognitoSQLiteManager.h" + +#import +#import "AWSCognitoUtil.h" +#import "AWSCognitoConstants.h" +#import "AWSCognitoDataset_Internal.h" +#import "AWSCognitoRecord_Internal.h" +#import +#import +#import "AWSCognitoConflict_Internal.h" +#import "AWSCognitoSyncService.h" + +@interface AWSCognitoSQLiteManager() +{ +} + +@property (nonatomic, assign) sqlite3 *sqlite; + +// iOS 6 and later, dispatch_queue_t is an Objective-C object. +#if OS_OBJECT_USE_OBJC +@property (nonatomic, strong) dispatch_queue_t dispatchQueue; +#else +@property (nonatomic, assign) dispatch_queue_t dispatchQueue; +#endif + +@end + +@implementation AWSCognitoSQLiteManager + +- (instancetype)initWithIdentityId:(NSString *)identityId deviceId:(NSString *)deviceId { + if(self = [super init]) + { + if (identityId == nil) { + identityId = AWSCognitoUnknownIdentity; + } + _identityId = identityId; + _deviceId = deviceId; + _dispatchQueue = dispatch_queue_create("com.amazon.cognito.SerialDispatchQueue", DISPATCH_QUEUE_SERIAL); + + [self setupSQL]; + [self initializeTables]; + } + + return self; +} + +- (void)setupSQL { + + + if(sqlite3_open([[self filePath] UTF8String], &_sqlite) != SQLITE_OK) + { + sqlite3_close(_sqlite); + AWSDDLogInfo(@"SQLite setup failed."); + + return; + } +} + +- (void)deleteAllData { + + dispatch_sync(self.dispatchQueue, ^{ + NSString *deleteString = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@ = ?", AWSCognitoDefaultSqliteDataTableName, AWSCognitoTableIdentityKeyName]; + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [deleteString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)) { + AWSDDLogError(@"Error deleting record data: %s", sqlite3_errmsg(self.sqlite)); + } + } + else { + AWSDDLogError(@"Error deleting dataset metadata: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + + deleteString = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@ = ?", AWSCognitoDefaultSqliteMetadataTableName, AWSCognitoTableIdentityKeyName]; + + if(sqlite3_prepare_v2(self.sqlite, [deleteString UTF8String], -1, &statement, NULL) == SQLITE_OK) { + sqlite3_bind_text(statement, 1, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + if(SQLITE_DONE != sqlite3_step(statement)) { + AWSDDLogError(@"Error deleting dataset metadata: %s", sqlite3_errmsg(self.sqlite)); + } + } + else + { + AWSDDLogError(@"Error deleting dataset metadata: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + + self.identityId = AWSCognitoUnknownIdentity; + }); +} + +- (void)initializeTables { + + dispatch_sync(self.dispatchQueue, ^{ + NSString *createString = [NSString stringWithFormat: + @"CREATE TABLE IF NOT EXISTS %@ ( \ + %@ TEXT NOT NULL DEFAULT %@, \ + %@ TEXT NOT NULL, \ + %@ TEXT NOT NULL, \ + %@ INTEGER NOT NULL, \ + %@ TEXT NOT NULL, \ + %@ TEXT NOT NULL, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + %@ INTEGER NOT NULL DEFAULT 1, \ + %@ INTEGER NOT NULL, PRIMARY KEY(%@,%@,%@))", + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoUnknownIdentity, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoTypeFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableRecordKeyName]; + + char *error; + if(sqlite3_exec(_sqlite, [createString UTF8String], NULL, NULL, &error) != SQLITE_OK) + { + sqlite3_close(_sqlite); + AWSDDLogInfo(@"SQLite setup failed: %s", error); + + return; + } + NSString *createString2 = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ ( \ + %@ TEXT NOT NULL DEFAULT %@, \ + %@ TEXT NOT NULL, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + %@ TEXT NOT NULL, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + %@ INTEGER NOT NULL DEFAULT 0, \ + PRIMARY KEY(%@,%@))", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoUnknownIdentity, + AWSCognitoTableDatasetKeyName, + AWSCognitoLastSyncCount, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoDatasetCreationDateFieldName, + AWSCognitoDataStorageFieldName, + AWSCognitoRecordCountFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName ]; + if(sqlite3_exec(_sqlite, [createString2 UTF8String], NULL, NULL, &error) != SQLITE_OK) + { + sqlite3_close(_sqlite); + AWSDDLogInfo(@"SQLite setup failed: %s", error); + + return; + } + + }); +} + +- (void)initializeDatasetTables:(NSString *) datasetName { + + dispatch_sync(self.dispatchQueue, ^{ + + + NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO %@(%@,%@,%@,%@,%@) VALUES (?,?,?,?,?)", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableDatasetKeyName, + AWSCognitoModifiedByFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoDatasetCreationDateFieldName, + AWSCognitoLastModifiedFieldName + ]; + + AWSDDLogDebug(@"sqlString = '%@'", sqlString); + + sqlite3_stmt *statement; + + NSDate *lastModified = [NSDate date]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [[self deviceId] UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 4, [AWSCognitoUtil getTimeMillisForDate:lastModified]); + sqlite3_bind_int64(statement, 5, [AWSCognitoUtil getTimeMillisForDate:lastModified]); + int status = sqlite3_step(statement); + + if((SQLITE_DONE != status) && (SQLITE_CONSTRAINT != status)) + { + AWSDDLogInfo(@"Error initializing sync count: %s", sqlite3_errmsg(self.sqlite)); + } + } + else + { + AWSDDLogInfo(@"Error initializing sync count: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); +} + +#pragma mark - Data manipulations + +- (NSArray *)getDatasets:(NSError **)error { + __block NSMutableArray *datasets = [NSMutableArray array]; + + dispatch_sync(self.dispatchQueue, ^{ + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@, %@, %@, %@ FROM %@ WHERE %@ = ?", + AWSCognitoTableDatasetKeyName, + AWSCognitoLastSyncCount, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoDatasetCreationDateFieldName, + AWSCognitoDataStorageFieldName, + AWSCognitoRecordCountFieldName, + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableIdentityKeyName]; + + AWSDDLogDebug(@"query = '%@'", query); + + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + NSString * identityId = [self identityId]; + + sqlite3_bind_text(statement, 1, [identityId UTF8String], -1, SQLITE_TRANSIENT); + + while (sqlite3_step(statement) == SQLITE_ROW) + { + char *datasetName = (char *) sqlite3_column_text(statement, 0); + int64_t syncCount = sqlite3_column_int64(statement, 1); + int64_t lastMod = sqlite3_column_int64(statement, 2); + char *lastModBy = (char *) sqlite3_column_text(statement, 3); + int64_t createDate = sqlite3_column_int64(statement, 4); + int64_t storage = sqlite3_column_int64(statement, 5); + int64_t recordCount = sqlite3_column_int64(statement, 6); + + AWSCognitoDatasetMetadata *metadata = [AWSCognitoDatasetMetadata new]; + metadata.name = [NSString stringWithUTF8String:datasetName]; + metadata.lastSyncCount = [NSNumber numberWithLongLong:syncCount]; + metadata.lastModifiedDate = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:lastMod]]; + metadata.lastModifiedBy = [NSString stringWithUTF8String:lastModBy]; + metadata.creationDate = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:createDate]]; + metadata.dataStorage = [NSNumber numberWithLongLong:storage]; + metadata.numRecords = [NSNumber numberWithLongLong:recordCount]; + + [datasets addObject:metadata]; + } + } + else + { + AWSDDLogInfo(@"Error creating query statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return datasets; +} + +- (void)loadDatasetMetadata:(AWSCognitoDatasetMetadata *)metadata error:(NSError **)error { + + dispatch_sync(self.dispatchQueue, ^{ + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@, %@, %@ FROM %@ WHERE %@ = ? and %@ = ?", + AWSCognitoLastSyncCount, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoDatasetCreationDateFieldName, + AWSCognitoDataStorageFieldName, + AWSCognitoRecordCountFieldName, + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoDatasetFieldName]; + + AWSDDLogDebug(@"query = '%@'", query); + + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [self.identityId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [metadata.name UTF8String], -1, SQLITE_TRANSIENT); + + if (sqlite3_step(statement) == SQLITE_ROW) + { + int64_t syncCount = sqlite3_column_int64(statement, 0); + int64_t lastMod = sqlite3_column_int64(statement, 1); + char *lastModBy = (char *) sqlite3_column_text(statement, 2); + int64_t createDate = sqlite3_column_int64(statement, 3); + int64_t storage = sqlite3_column_int64(statement, 4); + int64_t recordCount = sqlite3_column_int64(statement, 5); + + metadata.lastSyncCount = [NSNumber numberWithLongLong:syncCount]; + metadata.lastModifiedDate = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:lastMod]]; + metadata.lastModifiedBy = [NSString stringWithUTF8String:lastModBy]; + metadata.creationDate = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:createDate]]; + metadata.dataStorage = [NSNumber numberWithLongLong:storage]; + metadata.numRecords = [NSNumber numberWithLongLong:recordCount]; + } + } + else + { + AWSDDLogInfo(@"Error creating query statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); +} + + +- (BOOL)updateDatasetMetadata:(AWSCognitoDatasetMetadata *)dataset error:(NSError **)error { + __block BOOL success = YES; + NSDate *lastModified = [NSDate date]; + dispatch_sync(self.dispatchQueue, ^{ + NSString *updateString = [NSString stringWithFormat:@"UPDATE %@ SET \ + %@ = ?,\ + WHERE %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoLastModifiedFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [updateString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_int64(statement, 1,[AWSCognitoUtil getTimeMillisForDate:lastModified]); + sqlite3_bind_text(statement, 2, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, [dataset.name UTF8String], -1, SQLITE_TRANSIENT); + + int status = sqlite3_step(statement); + + if((SQLITE_DONE != status) && (SQLITE_CONSTRAINT != status)) + { + AWSDDLogInfo(@"Error while updating dataset metadata: %s", sqlite3_errmsg(self.sqlite)); + success = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + sqlite3_reset(statement); + } + else + { + AWSDDLogInfo(@"Error while updating dataset metadata: %s", sqlite3_errmsg(self.sqlite)); + success = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + sqlite3_finalize(statement); + }); + + if(success){ + dataset.lastModifiedDate = lastModified; + } + return success; +} + +- (BOOL)putDatasetMetadata:(NSArray *)datasets error:(NSError **)error { + + __block BOOL success = YES; + + dispatch_sync(self.dispatchQueue, ^{ + NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO %@(%@,%@,%@,%@,%@,%@,%@) VALUES (?,?,?,?,?,?,?)", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoDatasetCreationDateFieldName, + AWSCognitoDataStorageFieldName, + AWSCognitoRecordCountFieldName]; + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + for (AWSCognitoSyncDataset *dataset in datasets) { + int64_t lastModified = [AWSCognitoUtil getTimeMillisForDate:dataset.lastModifiedDate]; + int64_t createDate = [AWSCognitoUtil getTimeMillisForDate:dataset.lastModifiedDate]; + sqlite3_bind_text(statement, 1, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [dataset.datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 3, lastModified); + sqlite3_bind_text(statement, 4, [dataset.lastModifiedBy UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 5, createDate); + sqlite3_bind_int64(statement, 6, [dataset.dataStorage longLongValue]); + sqlite3_bind_int64(statement, 7, [dataset.numRecords longLongValue]); + + int status = sqlite3_step(statement); + + if((SQLITE_DONE != status) && (SQLITE_CONSTRAINT != status)) + { + AWSDDLogInfo(@"Error while updating sync count: %s", sqlite3_errmsg(self.sqlite)); + success = NO; + } + sqlite3_reset(statement); + } + } + else + { + AWSDDLogInfo(@"Error updating sync count: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_finalize(statement); + }); + + return success; +} + +- (AWSCognitoRecord *)getRecordById_internal:(NSString *)recordId datasetName:(NSString *)datasetName error:(NSError **)error sync:(BOOL) sync{ + __block AWSCognitoRecord *record = nil; + void (^getRecord)() = ^{ + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@, %@, %@ FROM %@ WHERE %@ = ? AND %@ = ? AND %@ = ?", + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableRecordKeyName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName + ]; + + AWSDDLogDebug(@"query = '%@'", query); + + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [recordId UTF8String], -1, SQLITE_TRANSIENT); + + NSString * identityId = [self identityId]; + + sqlite3_bind_text(statement, 2, [identityId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + + if (sqlite3_step(statement) == SQLITE_ROW) + { + int64_t lastMod = sqlite3_column_int64(statement, 0); + char *modByChars = (char *) sqlite3_column_text(statement, 1); + char *dataChars = (char *)sqlite3_column_text(statement, 2); + int64_t type = sqlite3_column_int64(statement, 3); + int64_t syncCount = sqlite3_column_int64(statement, 4); + int64_t dirtyInt = sqlite3_column_int64(statement, 5); + + NSString *modBy = [[NSString alloc] initWithUTF8String:modByChars]; + NSString *data = [[NSString alloc] initWithUTF8String:dataChars]; + + record = [[AWSCognitoRecord alloc] initWithId:recordId + data:[[AWSCognitoRecordValue alloc]initWithJson:data type:(int)type]]; + record.lastModifiedBy = modBy; + record.lastModified = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:lastMod]]; + record.dirtyCount = dirtyInt; + record.syncCount = syncCount; + } + } + else + { + AWSDDLogInfo(@"Error creating query statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }; + if(sync){ + dispatch_sync(self.dispatchQueue, getRecord); + }else{ + getRecord(); + } + + return record; +} + +- (AWSCognitoRecord *)getRecordById:(NSString *)recordId datasetName:(NSString *)datasetName error:(NSError **)error { + return [self getRecordById_internal:recordId datasetName:datasetName error:error sync:YES]; +} + +- (NSString *) identityId { + if(_identityId == nil) { + _identityId = AWSCognitoUnknownIdentity; + } + return _identityId; +} + +- (NSDictionary *)recordsUpdatedAfterLastSync:(NSString *) datasetName error:(NSError **)error +{ + __block NSMutableDictionary *newRecords = [NSMutableDictionary new]; + + dispatch_sync(self.dispatchQueue, ^{ + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@, %@, %@, %@ FROM %@ WHERE %@ != 0 AND %@ = ? AND %@ = ?", + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoDirtyFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + + sqlite3_stmt *statement; + + + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + NSString * identityId = [self identityId]; + sqlite3_bind_text(statement, 1, [identityId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + + while (sqlite3_step(statement) == SQLITE_ROW) + { + char *recordIDChars = (char *) sqlite3_column_text(statement, 0); + int64_t lastMod = sqlite3_column_int64(statement, 1); + char *modByChars = (char *) sqlite3_column_text(statement, 2); + char *dataChars = (char *)sqlite3_column_text(statement, 3); + int64_t type = sqlite3_column_int64(statement, 4); + int64_t syncCount = sqlite3_column_int64(statement, 5); + int64_t dirtyInt = sqlite3_column_int64(statement, 6); + + NSString *recordId = [[NSString alloc] initWithUTF8String:recordIDChars]; + NSString *modBy = [[NSString alloc] initWithUTF8String:modByChars]; + NSString *data = [[NSString alloc] initWithUTF8String:dataChars]; + + AWSCognitoRecord *record = [[AWSCognitoRecord alloc] initWithId:recordId + data:[[AWSCognitoRecordValue alloc] initWithJson:data type:(int)type]]; + record.lastModifiedBy = modBy; + record.lastModified = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:lastMod]]; + record.dirtyCount = dirtyInt; + record.syncCount = syncCount; + + [newRecords setObject:record forKey:record.recordId]; + } + } + else + { + AWSDDLogInfo(@"Error creating query statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + }); + + return [NSDictionary dictionaryWithDictionary:newRecords]; +} + +- (NSArray *)allRecords:(NSString*)datasetName +{ + __block NSMutableArray *allRecords = nil; + + dispatch_sync(self.dispatchQueue, ^{ + + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@, %@, %@, %@ FROM %@ WHERE %@ = ? AND %@ = ?", + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + + AWSCognitoRecord *record = nil; + + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + NSString * identityId = [self identityId]; + sqlite3_bind_text(statement, 1, [identityId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + + while (sqlite3_step(statement)==SQLITE_ROW) + { + if(!allRecords) + { + allRecords = [NSMutableArray new]; + } + + char *recordIdChars = (char *) sqlite3_column_text(statement, 0); + int64_t lastMod = sqlite3_column_int64(statement, 1); + char *modByChars = (char *) sqlite3_column_text(statement, 2); + char *dataChars = (char *)sqlite3_column_text(statement, 3); + int64_t type = sqlite3_column_int64(statement, 4); + int64_t syncCount = sqlite3_column_int64(statement, 5); + int64_t dirtyInt = sqlite3_column_int64(statement, 6); + + NSString *modBy = [[NSString alloc] initWithUTF8String:modByChars]; + NSString *dataString = [[NSString alloc] initWithUTF8String:dataChars]; + NSString *recordId = [[NSString alloc] initWithUTF8String:recordIdChars]; + AWSCognitoRecordValue *data = [[AWSCognitoRecordValue alloc] initWithJson:dataString type:(int)type]; + + record = [[AWSCognitoRecord alloc] initWithId:recordId data:data]; + record.lastModifiedBy = modBy; + record.lastModified = [AWSCognitoUtil millisSinceEpochToDate:[NSNumber numberWithLongLong:lastMod]]; + record.dirtyCount = dirtyInt; + record.syncCount = syncCount; + + [allRecords addObject:record]; + + } + } + else + { + AWSDDLogInfo(@"Error creating query statement: %s", sqlite3_errmsg(self.sqlite)); + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return allRecords; +} + +- (BOOL)putRecord:(AWSCognitoRecord *)record datasetName:(NSString *)datasetName error:(NSError **)error { + __block BOOL result = NO; + NSDate *lastModifiedDate = [NSDate date]; + dispatch_sync(self.dispatchQueue, ^{ + + sqlite3_stmt *statement; + + int64_t lastModified = [AWSCognitoUtil getTimeMillisForDate:lastModifiedDate]; + const char *recordID = [record.recordId UTF8String]; + const char *lastModifiedBy = [self.deviceId UTF8String]; + const char *data = [[record.data toJsonString] UTF8String]; + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + /** + * Inserts a new record or replaces the current record with a given record. + * Increment the dirty count if we are updating the data. + */ + NSString *sqlString = [NSString stringWithFormat: + @"INSERT OR REPLACE INTO %@ ( \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@ \ + ) VALUES ( \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + COALESCE((SELECT %@ FROM %@ WHERE %@ = ? AND %@ = ? AND %@ = ?)+1, 1), \ + ?, \ + ? )", + + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName, + + AWSCognitoDirtyFieldName, + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableRecordKeyName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName + ]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) { + sqlite3_bind_text(statement, 1, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 2, lastModified); + sqlite3_bind_text(statement, 3, lastModifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 4, data, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 5, record.data.type); + sqlite3_bind_int64(statement, 6, record.syncCount); + + sqlite3_bind_text(statement, 7, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 8, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 9, datasetNameChars, -1, SQLITE_TRANSIENT); + + sqlite3_bind_text(statement, 10, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 11, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE == sqlite3_step(statement)) { + result = YES; + } + else { + AWSDDLogInfo(@"Error while inserting data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + } + else { + AWSDDLogInfo(@"Error creating insert statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + if(result) { + record.lastModified = lastModifiedDate; + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return result; +} + +- (BOOL)conditionallyPutRecord:(AWSCognitoRecord *)record datasetName:(NSString*)datasetName withCurrentState:(AWSCognitoRecord *)currentState error:(NSError **)error { + sqlite3_stmt *statement; + + const char *recordID = [record.recordId UTF8String]; + + int64_t lastModified = [AWSCognitoUtil getTimeMillisForDate:record.lastModified]; + const char *modifiedBy = [record.lastModifiedBy UTF8String]; + const char *data = [[record.data toJsonString] UTF8String]; + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + if(currentState) { // Updates the local data with the new data from the remote. + int64_t currentLastModified = [AWSCognitoUtil getTimeMillisForDate:currentState.lastModified]; + const char *currentModifiedBy = [currentState.lastModifiedBy UTF8String]; + const char *currentData = [[currentState.data toJsonString] UTF8String]; + + NSString *sqlString = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ? \ + WHERE %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + ", + + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) { + sqlite3_bind_int64(statement, 1, lastModified); + + sqlite3_bind_text(statement, 2, modifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, data, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 4, record.data.type); + sqlite3_bind_int64(statement, 5, record.syncCount); + sqlite3_bind_int64(statement, 6, record.dirtyCount); + + sqlite3_bind_text(statement, 7, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 8, currentLastModified); + sqlite3_bind_text(statement, 9, currentModifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 10, currentData, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 11, currentState.syncCount); + sqlite3_bind_int64(statement, 12, currentState.dirtyCount); + sqlite3_bind_text(statement, 13, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 14, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)) { + AWSDDLogInfo(@"Error while updating data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + [self resetStatement:statement]; + return NO; + } + int numRows = sqlite3_changes(self.sqlite); + + //if no updates were made error out + if(numRows <1){ + NSString *errorMsg = @"local value changed"; + AWSDDLogInfo(@"Error while updating data: %@",errorMsg); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:errorMsg]; + } + [self resetStatement:statement]; + return NO; + } + } + else { + AWSDDLogInfo(@"Error creating update statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + [self resetStatement:statement]; + return NO; + } + } + else { // Inserts the new data from the remote. + NSString *sqlString = [NSString stringWithFormat: + @"INSERT INTO %@ ( \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@, \ + %@ \ + ) VALUES ( \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + ?, \ + ? \ + )", + + AWSCognitoDefaultSqliteDataTableName, + + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName, + AWSCognitoDirtyFieldName]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) { + sqlite3_bind_text(statement, 1, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 2, lastModified); + sqlite3_bind_text(statement, 3, modifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 4, data, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 5, record.data.type); + sqlite3_bind_int64(statement, 6, record.syncCount); + sqlite3_bind_text(statement, 7, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 8, datasetNameChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 9, 0); + + + if(SQLITE_DONE != sqlite3_step(statement)) { + AWSDDLogInfo(@"Error while inserting data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + [self resetStatement:statement]; + return NO; + } + } + else { + AWSDDLogInfo(@"Error creating insert statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + [self resetStatement:statement]; + return NO; + } + } + + [self resetStatement:statement]; + return YES; +} + +/** + * Resets and finalizes a statement + **/ +- (void)resetStatement:(sqlite3_stmt *) statement { + sqlite3_reset(statement); + sqlite3_finalize(statement); +} + +- (BOOL)conditionallyPutResolvedRecords:(NSArray *) resolvedRecords datasetName:(NSString*)datasetName error:(NSError **)error { + sqlite3_stmt *statement = nil; + NSString *sqlString = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ? \ + WHERE %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + AND %@ = ? \ + ", + + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + + AWSCognitoTableRecordKeyName, + AWSCognitoLastModifiedFieldName, + AWSCognitoModifiedByFieldName, + AWSCognitoRecordValueName, + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + + for(AWSCognitoResolvedConflict *resolved in resolvedRecords){ + AWSCognitoRecord * currentState = resolved.conflict.localRecord; + AWSCognitoRecord * record = resolved.resolvedConflict; + const char *recordID = [record.recordId UTF8String]; + + int64_t lastModified = [AWSCognitoUtil getTimeMillisForDate:record.lastModified]; + const char *modifiedBy = [record.lastModifiedBy UTF8String]; + const char *data = [[record.data toJsonString] UTF8String]; + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + + int64_t currentLastModified = [AWSCognitoUtil getTimeMillisForDate:currentState.lastModified]; + const char *currentModifiedBy = [currentState.lastModifiedBy UTF8String]; + const char *currentData = [[currentState.data toJsonString] UTF8String]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_int64(statement, 1, lastModified); + + sqlite3_bind_text(statement, 2, modifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, data, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 4, record.data.type); + sqlite3_bind_int64(statement, 5, record.syncCount); + sqlite3_bind_int64(statement, 6, record.dirtyCount); + + sqlite3_bind_text(statement, 7, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 8, currentLastModified); + sqlite3_bind_text(statement, 9, currentModifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 10, currentData, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 11, currentState.syncCount); + sqlite3_bind_int64(statement, 12, currentState.dirtyCount); + sqlite3_bind_text(statement, 13, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 14, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)){ + AWSDDLogInfo(@"Error while updating data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + [self resetStatement:statement]; + return NO; + } + } + + sqlite3_reset(statement); + } + sqlite3_finalize(statement); + return YES; +} + + +- (BOOL)flagRecordAsDeletedById:(NSString *)recordId datasetName:(NSString *) datasetName error:(NSError **)error +{ + __block BOOL result = NO; + + dispatch_sync(self.dispatchQueue, ^{ + + sqlite3_stmt *statement; + + int64_t lastModified = [AWSCognitoUtil getTimeMillisForDate:[NSDate date]]; + const char *recordID = [recordId UTF8String]; + const char *lastModifiedBy = [self.deviceId UTF8String]; + AWSCognitoRecordValue *value = [[AWSCognitoRecordValue alloc] initWithString:AWSCognitoDeletedRecord type:AWSCognitoRecordValueTypeDeleted]; + const char *data = [[value toJsonString] UTF8String]; + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + NSString *sqlString = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = %lld, \ + %@ = ?, \ + %@ = ?, \ + %@ = ?, \ + %@ = ? \ + WHERE %@ = ? AND %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteDataTableName, + + AWSCognitoDirtyFieldName, + AWSCognitoNotSyncedDeletedRecordDirty, + + AWSCognitoModifiedByFieldName, + AWSCognitoLastModifiedFieldName, + AWSCognitoRecordValueName, + AWSCognitoTypeFieldName, + AWSCognitoTableRecordKeyName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, lastModifiedBy, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 2, lastModified); + sqlite3_bind_text(statement, 3, data, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 4, value.type); + sqlite3_bind_text(statement, 5, recordID, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 6, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 7, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE == sqlite3_step(statement)) + { + result = YES; + } + else + { + AWSDDLogInfo(@"Error while inserting data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + } + else + { + AWSDDLogInfo(@"Error creating insert statement: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return result; +} + +- (BOOL)deleteRecordById:(NSString *)recordId datasetName:(NSString *) datasetName error:(NSError **)error +{ + __block BOOL result = NO; + + dispatch_sync(self.dispatchQueue, ^{ + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + NSString *statementString = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ? AND %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableRecordKeyName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName]; + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [statementString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [recordId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 3, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE == sqlite3_step(statement)) + { + result = YES; + } + else + { + AWSDDLogInfo(@"Error while deleting record: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + } + else + { + AWSDDLogInfo(@"Error while deleting record: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return result; +} + +- (BOOL)updateWithRemoteChanges:(NSString *)datasetName nonConflicts:(NSArray *)nonConflictRecords resolvedConflicts:(NSArray *)resolvedConflicts error:(NSError **)error { + __block BOOL result = YES; + dispatch_sync(self.dispatchQueue, ^{ + + // Do this as a single transaction + sqlite3_exec(self.sqlite, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0); + + // put the non-conflicts + for (AWSCognitoRecordTuple *tuple in nonConflictRecords) { + if (![self conditionallyPutRecord:tuple.remoteRecord datasetName:datasetName withCurrentState:tuple.localRecord error:error]) { + result = NO; + break; + } + } + + // put the conflicts if non-conflicts wrote + if (result) { + result = [self conditionallyPutResolvedRecords:resolvedConflicts datasetName:datasetName error:error]; + } + + if(result){ + if(sqlite3_exec(self.sqlite, "COMMIT TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error commiting reparent: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + }else if(sqlite3_exec(self.sqlite, "ROLLBACK TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error rolling back reparent: %s", sqlite3_errmsg(self.sqlite)); + //leave error message as is, don't overwrite it with the rollback error. + } + }); + return result; +} + +- (BOOL)updateLocalRecordMetadata:(NSString *)datasetName records:(NSArray *)updatedRecords error:(NSError **)error { + __block BOOL result = YES; + dispatch_sync(self.dispatchQueue, ^{ + // Do this as a single transaction + sqlite3_exec(self.sqlite, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0); + + // put the non-conflicts + for (AWSCognitoRecordTuple *tuple in updatedRecords) { + if (![self conditionallyPutRecord:tuple.remoteRecord datasetName:datasetName withCurrentState:tuple.localRecord error:error]) { + // if this failed, try just updating the sync count and let the next sync push + AWSCognitoRecord *existingRecord = [self getRecordById_internal:tuple.localRecord.recordId datasetName:datasetName error:error sync:NO]; + if (existingRecord != nil) { + AWSCognitoRecord *newRecord = [existingRecord copy]; + newRecord.syncCount = tuple.remoteRecord.syncCount; + if ([self conditionallyPutRecord:newRecord datasetName:datasetName withCurrentState:existingRecord error:error]) { + //clear the error we were able to recover + if(error != nil) + { + *error = nil; + } + continue; + } + } + result = NO; + break; + } + } + + if(result){ + if(sqlite3_exec(self.sqlite, "COMMIT TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error commiting reparent: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + }else if(sqlite3_exec(self.sqlite, "ROLLBACK TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error rolling back reparent: %s", sqlite3_errmsg(self.sqlite)); + //leave error message as is, don't overwrite it with the rollback error. + } + + }); + return result; +} + +//Gets number of records stored in SQLite +- (NSNumber *)numRecords:(NSString *)datasetName +{ + __block int64_t numRecords = 0; + + dispatch_sync(self.dispatchQueue, ^{ + NSString *query = [NSString stringWithFormat:@"SELECT COUNT(*) FROM %@ WHERE %@=? AND %@ = ?", + AWSCognitoDefaultSqliteDataTableName, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableIdentityKeyName]; + + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + + if (sqlite3_step(statement)==SQLITE_ROW) + { + numRecords = sqlite3_column_int64(statement, 0); + } + } + else + { + AWSDDLogInfo(@"Error creating num records count statement: %s", sqlite3_errmsg(self.sqlite)); + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return [NSNumber numberWithLongLong:numRecords]; +} + +#pragma mark - Sync table utilities + +//Gets last sync count stored in SQLite +- (NSNumber *)lastSyncCount:(NSString *)datasetName +{ + __block int64_t lastSyncCount = 0; + + dispatch_sync(self.dispatchQueue, ^{ + NSString *query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@=? AND %@ = ?", + AWSCognitoLastSyncCount, + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableIdentityKeyName]; + + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + + if (sqlite3_step(statement)==SQLITE_ROW) + { + lastSyncCount = sqlite3_column_int64(statement, 0); + } + } + else + { + AWSDDLogInfo(@"Error creating query sync count statement: %s", sqlite3_errmsg(self.sqlite)); + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + + return [NSNumber numberWithLongLong:lastSyncCount]; +} + +- (void)updateLastSyncCount:(NSString *)datasetName syncCount:(NSNumber *)syncCount lastModifiedBy:(NSString *)lastModifiedBy +{ + if (lastModifiedBy == nil) { + lastModifiedBy = self.deviceId; + } + + dispatch_sync(self.dispatchQueue, ^{ + NSString *sqlString = [NSString stringWithFormat:@"INSERT OR REPLACE INTO %@(%@,%@,%@,%@) VALUES (?,?,?,?)", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableDatasetKeyName, + AWSCognitoLastSyncCount, + AWSCognitoTableIdentityKeyName, + AWSCognitoModifiedByFieldName]; + sqlite3_stmt *statement; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 2, [syncCount longLongValue]); + sqlite3_bind_text(statement, 3, [[self identityId] UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 4, [lastModifiedBy UTF8String], -1, SQLITE_TRANSIENT); + + + if(SQLITE_DONE != sqlite3_step(statement)) + { + AWSDDLogInfo(@"Error while updating sync count: %s", sqlite3_errmsg(self.sqlite)); + } + } + else + { + AWSDDLogInfo(@"Error updating sync count: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); +} + + + +#pragma mark - Merge Utilties + +- (BOOL)reparentDatasets:(NSString *)oldId withNewId:(NSString *)newId error:(NSError **)error { + + __block BOOL result = YES; + + // get the existing datasets + NSArray *datasets = [self getDatasets:error]; + if (error != nil && *error != nil) { + return NO; + } + + // If the old id is nil, we want to just directly copy stuff over + NSString *datasetAppender = @""; + if (oldId == nil) { + oldId = AWSCognitoUnknownIdentity; + } + else { + datasetAppender = [NSString stringWithFormat:@".%@", oldId]; + } + + dispatch_sync(self.dispatchQueue, ^{ + + // Do this as a single transaction + sqlite3_exec(self.sqlite, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0); + + + NSString *updateMetadata = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = ?, \ + %@ = ? \ + WHERE %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteMetadataTableName, + + AWSCognitoDatasetFieldName, + AWSCognitoTableIdentityKeyName, + AWSCognitoDatasetFieldName, + AWSCognitoTableIdentityKeyName]; + + AWSDDLogDebug(@"updateMetadata = '%@'", updateMetadata); + + NSString *updateData = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = ?, \ + %@ = ? \ + WHERE %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteDataTableName, + + AWSCognitoTableDatasetKeyName, + AWSCognitoTableIdentityKeyName, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableIdentityKeyName]; + + AWSDDLogDebug(@"updateData = '%@'", updateData); + + sqlite3_stmt *updateMetadataStatement; + sqlite3_stmt *updateDataStatement; + + if((sqlite3_prepare_v2(self.sqlite, [updateMetadata UTF8String], -1, &updateMetadataStatement, NULL) != SQLITE_OK) || + (sqlite3_prepare_v2(self.sqlite, [updateData UTF8String], -1, &updateDataStatement, NULL) != SQLITE_OK)) { + AWSDDLogInfo(@"Error while reparenting data: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + else { + + // loop through and update each dataset + for (AWSCognitoDatasetMetadata *dataset in datasets) { + // name of merged dataset will be dataset.OLDID + NSString *newDatasetName = [NSString stringWithFormat:@"%@%@", dataset.name, datasetAppender]; + + sqlite3_bind_text(updateMetadataStatement, 1, [newDatasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateMetadataStatement, 2, [newId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateMetadataStatement, 3, [dataset.name UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateMetadataStatement, 4, [oldId UTF8String], -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(updateMetadataStatement)) { + AWSDDLogInfo(@"Error while reparenting data: %s", sqlite3_errmsg(self.sqlite)); + result = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + break; + } + + sqlite3_bind_text(updateDataStatement, 1, [newDatasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateDataStatement, 2, [newId UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateDataStatement, 3, [dataset.name UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateDataStatement, 4, [oldId UTF8String], -1, SQLITE_TRANSIENT); + + + if(SQLITE_DONE != sqlite3_step(updateDataStatement)) { + AWSDDLogInfo(@"Error while reparenting data: %s", sqlite3_errmsg(self.sqlite)); + result = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + break; + } + + sqlite3_reset(updateMetadataStatement); + sqlite3_reset(updateDataStatement); + } + sqlite3_finalize(updateMetadataStatement); + sqlite3_finalize(updateDataStatement); + } + if(result){ + if(sqlite3_exec(self.sqlite, "COMMIT TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error commiting reparent: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + }else if(sqlite3_exec(self.sqlite, "ROLLBACK TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error rolling back reparent: %s", sqlite3_errmsg(self.sqlite)); + //leave error message as is, don't overwrite it with the rollback error. + } + + }); + + return result; +} + +- (NSArray *)getMergeDatasets:(NSString *)datasetName error:(NSError **)error { + __block NSMutableArray *datasets = nil; + + dispatch_sync(self.dispatchQueue, ^{ + const char *datasetNameChars = [[NSString stringWithFormat:@"%@.%%", datasetName] UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + NSString *statementString = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = ? AND %@ LIKE ?", + AWSCognitoDatasetFieldName, + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableIdentityKeyName, + AWSCognitoDatasetFieldName]; + + AWSDDLogDebug(@"statementString = '%@'", statementString); + + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [statementString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, datasetNameChars, -1, SQLITE_TRANSIENT); + while (sqlite3_step(statement)==SQLITE_ROW) + { + if(!datasets) + { + datasets = [NSMutableArray new]; + } + char *nameChars = (char *) sqlite3_column_text(statement, 0); + NSString *name = [[NSString alloc] initWithUTF8String:nameChars]; + + [datasets addObject:name]; + } + } + else + { + AWSDDLogInfo(@"Error while getting merged datasets: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + + + }); + + return datasets; +} + +#pragma mark - Utilities + +- (NSString *)filePath +{ + NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentDirectory=[paths objectAtIndex:0]; + NSString *filePath = [documentDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite3", AWSCognitoDefaultSqliteDataTableName]]; + AWSDDLogDebug(@"Local database is: %@", filePath); + return filePath; +} + +- (BOOL)resetSyncCount:(NSString *)datasetName error:(NSError **)error { + __block BOOL result = YES; + + dispatch_sync(self.dispatchQueue, ^{ + // Do this as a single transaction + sqlite3_exec(self.sqlite, "BEGIN EXCLUSIVE TRANSACTION", 0, 0, 0); + + + NSString *updateMetadata = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = 0 \ + WHERE %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteMetadataTableName, + + AWSCognitoLastSyncCount, + AWSCognitoDatasetFieldName, + AWSCognitoTableIdentityKeyName]; + + AWSDDLogDebug(@"updateMetadata = '%@'", updateMetadata); + + NSString *updateData = [NSString stringWithFormat: + @"UPDATE %@ SET \ + %@ = 0, \ + %@ = 1 \ + WHERE %@ = ? AND %@ = ?", + AWSCognitoDefaultSqliteDataTableName, + + AWSCognitoSyncCountFieldName, + AWSCognitoDirtyFieldName, + AWSCognitoTableDatasetKeyName, + AWSCognitoTableIdentityKeyName]; + + AWSDDLogDebug(@"updateData = '%@'", updateData); + + sqlite3_stmt *updateMetadataStatement; + sqlite3_stmt *updateDataStatement; + + if((sqlite3_prepare_v2(self.sqlite, [updateMetadata UTF8String], -1, &updateMetadataStatement, NULL) != SQLITE_OK) || + (sqlite3_prepare_v2(self.sqlite, [updateData UTF8String], -1, &updateDataStatement, NULL) != SQLITE_OK)) { + AWSDDLogInfo(@"Error while resetting sync count: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + else { + sqlite3_bind_text(updateMetadataStatement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateMetadataStatement, 2, [self.identityId UTF8String], -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(updateMetadataStatement)) { + AWSDDLogInfo(@"Error while resetting sync count: %s", sqlite3_errmsg(self.sqlite)); + result = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(updateMetadataStatement); + sqlite3_reset(updateDataStatement); + + if (result) { + sqlite3_bind_text(updateDataStatement, 1, [datasetName UTF8String], -1, SQLITE_TRANSIENT); + sqlite3_bind_text(updateDataStatement, 2, [self.identityId UTF8String], -1, SQLITE_TRANSIENT); + + + if(SQLITE_DONE != sqlite3_step(updateDataStatement)) { + AWSDDLogInfo(@"Error while resetting sync count: %s", sqlite3_errmsg(self.sqlite)); + result = NO; + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + return; + } + + sqlite3_finalize(updateMetadataStatement); + sqlite3_finalize(updateDataStatement); + } + } + if(result){ + if(sqlite3_exec(self.sqlite, "COMMIT TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error commiting reset: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + result = NO; + } + }else if(sqlite3_exec(self.sqlite, "ROLLBACK TRANSACTION",0,0,0)!=SQLITE_OK){ + AWSDDLogInfo(@"Error rolling back reset: %s", sqlite3_errmsg(self.sqlite)); + //leave error message as is, don't overwrite it with the rollback error. + } + + }); + + return result; +} + +- (BOOL)deleteMetadata:(NSString *)datasetName error:(NSError **)error { + __block BOOL result = NO; + + dispatch_sync(self.dispatchQueue, ^{ + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + NSString *statementString = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@=? AND %@=?", AWSCognitoDefaultSqliteMetadataTableName, AWSCognitoTableIdentityKeyName, AWSCognitoDatasetFieldName]; + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [statementString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)) + { + AWSDDLogInfo(@"Error while deleting metadata: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + + }else{ + result = YES; + } + } + else + { + AWSDDLogInfo(@"Error while deleting metadata: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + } + + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + return result; +} + +- (BOOL)deleteDataset:(NSString *) datasetName error:(NSError **)error +{ + __block BOOL result = NO; + + dispatch_sync(self.dispatchQueue, ^{ + + NSString *statementString = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ? AND %@ = ?", AWSCognitoDefaultSqliteDataTableName, AWSCognitoTableIdentityKeyName, AWSCognitoTableDatasetKeyName]; + sqlite3_stmt *statement; + + const char *datasetNameChars = [datasetName UTF8String]; + const char *identityIdChars = [[self identityId] UTF8String]; + + if(sqlite3_prepare_v2(self.sqlite, [statementString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 2, datasetNameChars, -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)) + { + AWSDDLogInfo(@"Error while clearing table: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + + } + } + else + { + AWSDDLogInfo(@"Error while clearing table: %s", sqlite3_errmsg(self.sqlite)); + if(error != nil) + { + *error = [AWSCognitoUtil errorLocalDataStorageFailed:[NSString stringWithFormat:@"%s", sqlite3_errmsg(self.sqlite)]]; + } + + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + + NSString *sqlString = [NSString stringWithFormat:@"INSERT OR REPLACE INTO %@(%@,%@,%@,%@) VALUES (?,?,?,?)", + AWSCognitoDefaultSqliteMetadataTableName, + AWSCognitoTableDatasetKeyName, + AWSCognitoLastSyncCount, + AWSCognitoTableIdentityKeyName, + AWSCognitoModifiedByFieldName]; + + if(sqlite3_prepare_v2(self.sqlite, [sqlString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + sqlite3_bind_text(statement, 1, datasetNameChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(statement, 2, -1); + sqlite3_bind_text(statement, 3, identityIdChars, -1, SQLITE_TRANSIENT); + sqlite3_bind_text(statement, 4, [[self deviceId] UTF8String], -1, SQLITE_TRANSIENT); + + if(SQLITE_DONE != sqlite3_step(statement)) + { + AWSDDLogInfo(@"Error while updating sync count: %s", sqlite3_errmsg(self.sqlite)); + }else { + result = YES; + } + } + else + { + AWSDDLogInfo(@"Error updating sync count: %s", sqlite3_errmsg(self.sqlite)); + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + + }); + return result; +} + +-(BOOL)columnExists:(NSString *) tableName columnName:(NSString *) columnName; +{ + __block BOOL result = NO; + + dispatch_sync(self.dispatchQueue, ^{ + + NSString *statementString = [NSString stringWithFormat:@"SELECT %@ FROM %@", columnName, tableName]; + sqlite3_stmt *statement; + if(sqlite3_prepare_v2(self.sqlite, [statementString UTF8String], -1, &statement, NULL) == SQLITE_OK) + { + result = YES; + } + sqlite3_reset(statement); + sqlite3_finalize(statement); + }); + return result; +} + +- (void)deleteSQLiteDatabase +{ + dispatch_sync(self.dispatchQueue, ^{ + if([[NSFileManager defaultManager] fileExistsAtPath:[self filePath]]) + { + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:[self filePath] error:&error]; + if (error) { + AWSDDLogDebug(@"Error deleting DB file %@", error); + } + } + }); +} + +#pragma mark - + +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.h b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.h new file mode 100644 index 00000000..f4836779 --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.h @@ -0,0 +1,80 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoRecord.h" +#import "AWSCognitoSyncModel.h" + +@interface AWSCognitoUtil : NSObject + +/** + * Convert milliseconds since epoch to NSDate, with clock skew adjustment for the given date. + * + * @param millisSinceEpoch number of milliseconds since epoch + * + * @return NSDate + */ ++ (NSDate *)millisSinceEpochToDate:(NSNumber *)millisSinceEpoch; + +/** + * Convert seconds since epoch to NSDate, with clock skew adjustment for the given date. + * + * @param secondsSinceEpoch number of seconds since epoch + * + * @return NSDate + */ ++ (NSDate *)secondsSinceEpochToDate:(NSNumber *)secondsSinceEpoch; + + +/** + * Get the epoch time in milliseconds, with clock skew adjustment for the given date. + * + * @param date The date to be converted to milliseconds + * + * @return The epoch time in milliseconds as a long long + */ ++ (long long)getTimeMillisForDate:(NSDate *)date; + ++ (NSError *)errorRemoteDataStorageFailed:(NSString *)failureReason; ++ (NSError *)errorInvalidDataValue:(NSString *)failureReason key:(NSString *)key value:(id)value; ++ (NSError *)errorUserDataSizeLimitExceeded:(NSString *)failureReason; ++ (NSError *)errorLocalDataStorageFailed:(NSString *)failureReason; ++ (NSError *)errorIllegalArgument:(NSString *)failureReason; + ++ (id)retrieveValue:(AWSCognitoRecordValue *)value; + ++ (BOOL)isValidRecordValueType:(AWSCognitoRecordValueType)type; + +/** + * Get the push platform string for this build target + */ ++ (NSString *) pushPlatformString:(AWSCognitoSyncPlatform) pushPlatform; + +/** + * Get the push platform for this build target + */ ++ (AWSCognitoSyncPlatform) pushPlatform; + +/** + * Get the device id key for this push platform string + */ ++ (NSString *) deviceIdKey:(AWSCognitoSyncPlatform) pushPlatformString; + +/** + * Get the device identity key for this push platform string + */ ++ (NSString *) deviceIdentityKey:(AWSCognitoSyncPlatform) pushPlatformString; +@end diff --git a/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.m b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.m new file mode 100644 index 00000000..7edb4e1a --- /dev/null +++ b/ios/Pods/AWSCognito/AWSCognito/Internal/AWSCognitoUtil.m @@ -0,0 +1,211 @@ +// +// Copyright 2014-2016 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the +// License. A copy of the License is located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, express or implied. See the License +// for the specific language governing permissions and +// limitations under the License. +// + +#import "AWSCognitoService.h" +#import "AWSCognitoUtil.h" + +#import +#import "AWSCognitoConstants.h" +#import "AWSCognitoRecord_Internal.h" + +@implementation AWSCognitoUtil + ++(NSDate *)millisSinceEpochToDate:(NSNumber *)millisSinceEpoch +{ + return [NSDate dateWithTimeIntervalSince1970:([millisSinceEpoch doubleValue] / 1000)]; +} + ++(NSDate *)secondsSinceEpochToDate:(NSNumber *)secondsSinceEpoch +{ + return [NSDate dateWithTimeIntervalSince1970:([secondsSinceEpoch doubleValue])]; +} + + ++ (long long)getTimeMillisForDate:(NSDate *)date +{ + if (date == nil) + { + date = [NSDate date]; + } + NSTimeInterval epochSeconds = [date timeIntervalSince1970]; + NSTimeInterval adjustedSeconds = [[AWSCognitoUtil secondsSinceEpochToDate:[NSNumber numberWithDouble:epochSeconds]] timeIntervalSince1970]; + long long adjustedMilliseconds = round(adjustedSeconds * 1000); + + return adjustedMilliseconds; +} + ++ (NSString *)hexEncode:(NSString *)string +{ + NSUInteger len = [string length]; + unichar *chars = malloc(len * sizeof(unichar)); + + [string getCharacters:chars]; + + NSMutableString *hexString = [[NSMutableString alloc] init]; + for (NSUInteger i = 0; i < len; i++) { + if ((int)chars[i] < 16) { + [hexString appendString:@"0"]; + } + [hexString appendString:[NSString stringWithFormat:@"%x", chars[i]]]; + } + free(chars); + + return hexString; +} + +#pragma mark - Error object generations + ++ (NSError *)errorRemoteDataStorageFailed:(NSString *)failureReason +{ + NSDictionary *userInfo = nil; + if(failureReason) + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorRemoteDataStorageFailedDescription, + NSLocalizedFailureReasonErrorKey : failureReason, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorRemoteDataStorageFailedRecoverySuggestion}; + } + else + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorRemoteDataStorageFailedDescription, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorRemoteDataStorageFailedRecoverySuggestion}; + } + + return [NSError errorWithDomain:AWSCognitoErrorDomain + code:AWSCognitoErrorRemoteDataStorageFailed + userInfo:userInfo]; +} + ++ (NSError *)errorInvalidDataValue:(NSString *)failureReason key:(NSString *)key value:(id)value +{ + NSDictionary *userInfo = nil; + if(failureReason) + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorInvalidDataValueDescription, + NSLocalizedFailureReasonErrorKey : failureReason, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorInvalidDataValueRecoverySuggestion, + @"key" : key, + @"value" : value}; + } + else + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorInvalidDataValueDescription, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorInvalidDataValueRecoverySuggestion}; + } + + return [NSError errorWithDomain:AWSCognitoErrorDomain + code:AWSCognitoErrorInvalidDataValue + userInfo:userInfo]; +} + ++ (NSError *)errorUserDataSizeLimitExceeded:(NSString *)failureReason +{ + NSDictionary *userInfo = nil; + if(failureReason) + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorUserDataSizeLimitExceededDescription, + NSLocalizedFailureReasonErrorKey : failureReason, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorUserDataSizeLimitExceededRecoverySuggestion}; + } + else + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorUserDataSizeLimitExceededDescription, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorUserDataSizeLimitExceededRecoverySuggestion}; + } + + return [NSError errorWithDomain:AWSCognitoErrorDomain + code:AWSCognitoErrorUserDataSizeLimitExceeded + userInfo:userInfo]; +} + ++ (NSError *)errorLocalDataStorageFailed:(NSString *)failureReason +{ + NSDictionary *userInfo = nil; + if(failureReason) + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorLocalDataStorageFailedDescription, + NSLocalizedFailureReasonErrorKey : failureReason, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorLocalDataStorageFailedRecoverySuggestion}; + } + else + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorLocalDataStorageFailedDescription, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorLocalDataStorageFailedRecoverySuggestion}; + } + + return [NSError errorWithDomain:AWSCognitoErrorDomain + code:AWSCognitoErrorLocalDataStorageFailed + userInfo:userInfo]; +} + ++ (NSError *)errorIllegalArgument:(NSString *)failureReason +{ + NSDictionary *userInfo = nil; + if(failureReason) + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorIllegalArgumentDescription, + NSLocalizedFailureReasonErrorKey : failureReason, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorIllegalArgumentRecoverySuggestion}; + } + else + { + userInfo = @{NSLocalizedDescriptionKey : AWSCognitoErrorIllegalArgumentDescription, + NSLocalizedRecoverySuggestionErrorKey : AWSCognitoErrorIllegalArgumentRecoverySuggestion}; + } + + return [NSError errorWithDomain:AWSCognitoErrorDomain + code:AWSCognitoErrorIllegalArgument + userInfo:userInfo]; +} + +#pragma mark - Sets and array conversion helpers + ++ (id)retrieveValue:(AWSCognitoRecordValue *)value { + if(value.type == AWSCognitoRecordValueTypeString) { + return value.string; + } + + return nil; +} + +#pragma mark Type validation ++ (BOOL)isValidRecordValueType:(AWSCognitoRecordValueType)type { + return type >= AWSCognitoRecordValueTypeUnknown && type <= AWSCognitoRecordValueTypeDeleted; +} + + +#pragma mark Push notifications ++ (NSString *) pushPlatformString: (AWSCognitoSyncPlatform) pushPlatform { + return (AWSCognitoSyncPlatformApns == pushPlatform)? AWSCognitoSyncPushApns : AWSCognitoSyncPushApnsSandbox; +} + ++ (AWSCognitoSyncPlatform) pushPlatform { + #ifdef DEBUG + return AWSCognitoSyncPlatformApnsSandbox; + #else + return AWSCognitoSyncPlatformApns; + #endif +} + ++ (NSString *) deviceIdKey:(AWSCognitoSyncPlatform) pushPlatform { + return [NSString stringWithFormat:@"Cognito-%@-DeviceId", [AWSCognitoUtil pushPlatformString:pushPlatform]]; +} + ++ (NSString *) deviceIdentityKey:(AWSCognitoSyncPlatform) pushPlatform { + return [NSString stringWithFormat:@"Cognito-%@-DeviceIdentity", [AWSCognitoUtil pushPlatformString:pushPlatform]]; +} + +@end diff --git a/ios/Pods/AWSCognito/LICENSE b/ios/Pods/AWSCognito/LICENSE new file mode 100644 index 00000000..da144d8a --- /dev/null +++ b/ios/Pods/AWSCognito/LICENSE @@ -0,0 +1 @@ +The AWS Mobile SDK for iOS is generally licensed under the Apache 2.0 License, with the Amazon Cognito Identity Provider and Amazon Cognito Sync subcomponents being licensed under the Amazon Software License and the AWSLex/Bluefront folder under the AWS Customer Agreement (https://aws.amazon.com/agreement/ ). diff --git a/ios/Pods/AWSCognito/LICENSE.AMAZON b/ios/Pods/AWSCognito/LICENSE.AMAZON new file mode 100644 index 00000000..0945c46f --- /dev/null +++ b/ios/Pods/AWSCognito/LICENSE.AMAZON @@ -0,0 +1,27 @@ +Amazon Software License +This Amazon Software License (“License”) governs your use, reproduction, and distribution of the accompanying software as specified below. +1. Definitions +“Licensor” means any person or entity that distributes its Work. + +“Software” means the original work of authorship made available under this License. + +“Work” means the Software and any additions to or derivative works of the Software that are made available under this License. + +The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have the meaning as provided under U.S. copyright law; provided, however, that for the purposes of this License, derivative works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work. + +Works, including the Software, are “made available” under this License by including in or with the Work either (a) a copyright notice referencing the applicability of this License to the Work, or (b) a copy of this License. +2. License Grants +2.1 Copyright Grant. Subject to the terms and conditions of this License, each Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free, copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute its Work and any resulting derivative works in any form. +2.2 Patent Grant. Subject to the terms and conditions of this License, each Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free patent license to make, have made, use, sell, offer for sale, import, and otherwise transfer its Work, in whole or in part. The foregoing license applies only to the patent claims licensable by Licensor that would be infringed by Licensor’s Work (or portion thereof) individually and excluding any combinations with any other materials or technology. +3. Limitations +3.1 Redistribution. You may reproduce or distribute the Work only if (a) you do so under this License, (b) you include a complete copy of this License with your distribution, and (c) you retain without modification any copyright, patent, trademark, or attribution notices that are present in the Work. +3.2 Derivative Works. You may specify that additional or different terms apply to the use, reproduction, and distribution of your derivative works of the Work (“Your Terms”) only if (a) Your Terms provide that the use limitation in Section 3.3 applies to your derivative works, and (b) you identify the specific derivative works that are subject to Your Terms. Notwithstanding Your Terms, this License (including the redistribution requirements in Section 3.1) will continue to apply to the Work itself. +3.3 Use Limitation. The Work and any derivative works thereof only may be used or intended for use with the web services, computing platforms or applications provided by Amazon.com, Inc. or its affiliates, including Amazon Web Services, Inc. +3.4 Patent Claims. If you bring or threaten to bring a patent claim against any Licensor (including any claim, cross-claim or counterclaim in a lawsuit) to enforce any patents that you allege are infringed by any Work, then your rights under this License from such Licensor (including the grants in Sections 2.1 and 2.2) will terminate immediately. +3.5 Trademarks. This License does not grant any rights to use any Licensor’s or its affiliates’ names, logos, or trademarks, except as necessary to reproduce the notices described in this License. +3.6 Termination. If you violate any term of this License, then your rights under this License (including the grants in Sections 2.1 and 2.2) will terminate immediately. +4. Disclaimer of Warranty. +THE WORK IS PROVIDED “AS IS” WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF M ERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER THIS LICENSE. SOME STATES’ CONSUMER LAWS DO NOT ALLOW EXCLUSION OF AN IMPLIED WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO YOU. +5. Limitation of Liability. +EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK (INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMM ERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +Effective Date – April 18, 2008 © 2008 Amazon.com, Inc. or its affiliates. All rights reserved. \ No newline at end of file diff --git a/ios/Pods/AWSCognito/LICENSE.APACHE b/ios/Pods/AWSCognito/LICENSE.APACHE new file mode 100644 index 00000000..2c993182 --- /dev/null +++ b/ios/Pods/AWSCognito/LICENSE.APACHE @@ -0,0 +1,51 @@ +Apache License +Version 2.0, January 2004 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/ios/Pods/AWSCognito/README.md b/ios/Pods/AWSCognito/README.md new file mode 100644 index 00000000..7eae9950 --- /dev/null +++ b/ios/Pods/AWSCognito/README.md @@ -0,0 +1,502 @@ +# AWS Mobile SDK for iOS + +[![Release](https://img.shields.io/github/release/aws/aws-sdk-ios.svg)]() +[![CocoaPods](https://img.shields.io/cocoapods/v/AWSiOSSDKv2.svg)]() +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Twitter Follow](https://img.shields.io/twitter/follow/AWSforMobile.svg?style=social&label=Follow)](https://twitter.com/AWSforMobile) + +## Setting Up + +To get started with the AWS SDK for iOS, you can set up the SDK and start building a new project, or you integrate the SDK in an existing project. You can also run the samples to get a sense of how the SDK works. + +To use the AWS SDK for iOS, you will need the following installed on your development machine: + +* Xcode 7 or later +* iOS 8 or later + +At the AWS GitHub repo, you can check out the [SDK source code](https://github.com/aws/aws-sdk-ios). + +For more information, see [AWS Mobile SDK for iOS Developer Guide](http://docs.aws.amazon.com/mobile/sdkforios/developerguide/). + +## Include the SDK for iOS in an Existing Application + +The [samples](https://github.com/awslabs/aws-sdk-ios-samples) included with the SDK for iOS are standalone projects that are already set up for you. You can also integrate the SDK for iOS with your own existing project. There are three ways to import the AWS Mobile SDK for iOS into your project: + +* [CocoaPods](https://cocoapods.org/) +* [Carthage](https://github.com/Carthage/Carthage) +* [Dynamic Frameworks](https://aws.amazon.com/mobile/sdk/) + +You should use one of these three ways to import the AWS Mobile SDK but not multiple. Importing the SDK in multiple ways loads duplicate copies of the SDK into the project and causes compiler errors. + +### CocoaPods + +1. The AWS Mobile SDK for iOS is available through [CocoaPods](http://cocoapods.org). If you have not installed CocoaPods, install CocoaPods by running the command: + + $ gem install cocoapods + $ pod setup + + Depending on your system settings, you may have to use `sudo` for installing `cocoapods` as follows: + + $ sudo gem install cocoapods + $ pod setup + +1. In your project directory (the directory where your `*.xcodeproj` file is), create a plain text file named `Podfile` (without any file extension) and add the lines below. Replace `YourTarget` with your actual target name. + + source 'https://github.com/CocoaPods/Specs.git' + + platform :ios, '8.0' + use_frameworks! + + target :'YourTarget' do + pod 'AWSAutoScaling' + pod 'AWSCloudWatch' + pod 'AWSCognito' + pod 'AWSCognitoIdentityProvider' + pod 'AWSDynamoDB' + pod 'AWSEC2' + pod 'AWSElasticLoadBalancing' + pod 'AWSIoT' + pod 'AWSKinesis' + pod 'AWSLambda' + pod 'AWSMachineLearning' + pod 'AWSMobileAnalytics' + pod 'AWSS3' + pod 'AWSSES' + pod 'AWSSimpleDB' + pod 'AWSSNS' + pod 'AWSSQS' + end + + ![image](readme-images/cocoapods-setup-01.png?raw=true) + +1. Then run the following command: + + $ pod install + +1. Open up `*.xcworkspace` with Xcode and start using the SDK. + + ![image](readme-images/cocoapods-setup-02.png?raw=true) + + **Note**: Do **NOT** use `*.xcodeproj`. If you open up a project file instead of a workspace, you receive an error: + + ld: library not found for -lPods-AWSCore + clang: error: linker command failed with exit code 1 (use -v to see invocation) + +### Carthage + +1. Install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage). + +1. Add the following to your `Cartfile`: + + github "aws/aws-sdk-ios" + +1. Then run the following command: + + $ carthage update + +1. With your project open in Xcode, select your **Target**. Under **General** tab, find **Embedded Binaries** and then click the **+** button. + +1. Click the **Add Other...** button, navigate to the `AWS<#ServiceName#>.framework` files under `Carthage` > `Build` > `iOS` and select them. Do not check the **Destination: Copy items if needed** checkbox when prompted. + + * `AWSCore.framework` + * `AWSAutoScaling.framework` + * `AWSCloudWatch.framework` + * `AWSCognito.framework` + * `AWSCognitoIdentityProvider.framework` + * `AWSDynamoDB.framework` + * `AWSEC2.framework` + * `AWSElasticLoadBalancing.framework` + * `AWSIoT.framework` + * `AWSKinesis.framework` + * `AWSLambda.framework` + * `AWSMachineLearning.framework` + * `AWSMobileAnalytics.framework` + * `AWSS3.framework` + * `AWSSES.framework` + * `AWSSimpleDB.framework` + * `AWSSNS.framework` + * `AWSSQS.framework` + +1. Under the **Build Phases** tab in your **Target**, click the **+** button on the top left and then select **New Run Script Phase**. Then setup the build phase as follows. Make sure this phase is below the `Embed Frameworks` phase. + + Shell /bin/sh + + bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSCore.framework/strip-frameworks.sh" + + Show environment variables in build log: Checked + Run script only when installing: Not checked + + Input Files: Empty + Output Files: Empty + +### Frameworks + +1. Download the SDK from our [AWS Mobile SDK](http://aws.amazon.com/mobile/sdk) page. The SDK is stored in a compressed file archive named `aws-ios-sdk-#.#.#` (where `#.#.#` represents the version number, so for version 2.5.0, the filename is `aws-ios-sdk-2.5.0`). + +1. With your project open in Xcode, select your **Target**. Under **General** tab, find **Embedded Binaries** and then click the **+** button. + +1. Click the **Add Other...** button, navigate to the `AWS<#ServiceName#>.framework` files and select them. Check the **Destination: Copy items if needed** checkbox when prompted. + + * `AWSCore.framework` + * `AWSAutoScaling.framework` + * `AWSCloudWatch.framework` + * `AWSCognito.framework` + * `AWSCognitoIdentityProvider.framework` + * `AWSDynamoDB.framework` + * `AWSEC2.framework` + * `AWSElasticLoadBalancing.framework` + * `AWSIoT.framework` + * `AWSKinesis.framework` + * `AWSLambda.framework` + * `AWSMachineLearning.framework` + * `AWSMobileAnalytics.framework` + * `AWSS3.framework` + * `AWSSES.framework` + * `AWSSimpleDB.framework` + * `AWSSNS.framework` + * `AWSSQS.framework` + +1. Under the **Buid Phases** tab in your **Target**, click the **+** button on the top left and then select **New Run Script Phase**. Then setup the build phase as follows. Make sure this phase is below the `Embed Frameworks` phase. + + Shell /bin/sh + + bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSCore.framework/strip-frameworks.sh" + + Show environment variables in build log: Checked + Run script only when installing: Not checked + + Input Files: Empty + Output Files: Empty + +## Update the SDK to a Newer Version + +When we release a new version of the SDK, you can pick up the changes as described below. + +### CocoaPods + +1. Run the following command in your project directory. CocoaPods automatically picks up the new changes. + + $ pod update + + **Note**: If your pod is having an issue, you can delete `Podfile.lock` and `Pods/` then run `pod install` to cleanly install the SDK. + + ![image](readme-images/cocoapods-setup-03.png?raw=true) + +### Carthage + +1. Run the following command in your project directory. Carthage automatically picks up the new changes. + + $ carthage update + +### Frameworks + +1. In Xcode select the following frameworks in **Project Navigator** and hit **delete** on your keyboard. Then select **Move to Trash**: + + * `AWSCore.framework` + * `AWSAutoScaling.framework` + * `AWSCloudWatch.framework` + * `AWSCognito.framework` + * `AWSCognitoIdentityProvider.framework` + * `AWSDynamoDB.framework` + * `AWSEC2.framework` + * `AWSElasticLoadBalancing.framework` + * `AWSIoT.framework` + * `AWSKinesis.framework` + * `AWSLambda.framework` + * `AWSMachineLearning.framework` + * `AWSMobileAnalytics.framework` + * `AWSS3.framework` + * `AWSSES.framework` + * `AWSSimpleDB.framework` + * `AWSSNS.framework` + * `AWSSQS.framework` + +1. Follow the installation process above to include the new version of the SDK. + +## Preparing your apps for iOS 9 +The release of iOS 9 includes changes that might impact how your apps interact with some AWS services. If you compile your apps with Apple’s iOS 9 SDK (or Xcode 7), Apple’s [App Transport Security (ATS)](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html) feature may affect the ability of apps to connect to certain AWS service endpoints. In order to ensure affected apps continue to successfully connect to AWS endpoints, you’ll need to configure them to interact properly with Apple’s ATS by adding these properties to your `Info.plist` file: + + NSAppTransportSecurity + + NSExceptionDomains + + amazonaws.com + + NSThirdPartyExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + NSIncludesSubdomains + + + amazonaws.com.cn + + NSThirdPartyExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + NSIncludesSubdomains + + + + + +For more information, see [Preparing Your Apps for iOS 9](http://docs.aws.amazon.com/mobile/sdkforios/developerguide/ats.html). + +## Getting Started with Swift + +1. Import the AWSCore header in the application delegate. + + import AWSCore + +1. Create a default service configuration by adding the following code snippet in the `application:didFinishLaunchingWithOptions:` application delegate method. + + let credentialsProvider = AWSCognitoCredentialsProvider( + regionType: CognitoRegionType, + identityPoolId: CognitoIdentityPoolId) + let configuration = AWSServiceConfiguration( + region: DefaultServiceRegionType, + credentialsProvider: credentialsProvider) + AWSServiceManager.default().defaultServiceConfiguration = configuration + +1. In Swift file you want to use the SDK, import the appropriate headers for the services you are using. The header file import convention is `import AWSServiceName`, as in the following examples: + + import AWSS3 + import AWSDynamoDB + import AWSSQS + import AWSSNS + import AWSCognito + +1. Make a call to the AWS services. + + let dynamoDB = AWSDynamoDB.default() + let listTableInput = AWSDynamoDBListTablesInput() + dynamoDB.listTables(listTableInput!).continueWith { (task:AWSTask) -> Any? in + if let error = task.error as? NSError { + print("Error occurred: \(error)") + return nil + } + + let listTablesOutput = task.result + + for tableName in listTablesOutput!.tableNames! { + print("\(tableName)") + } + + return nil + } + + **Note**: Most of the service client classes have a singleton method to get a default client. The naming convention is `+ defaultSERVICENAME` (e.g. `+ defaultDynamoDB` in the above code snippet). This singleton method creates a service client with `defaultServiceConfiguration`, which you set up in step 5, and maintains a strong reference to the client. + +## Getting Started with Objective-C + +1. Import the AWSCore header in the application delegate. + + @import AWSCore; + +1. Create a default service configuration by adding the following code snippet in the `application:didFinishLaunchingWithOptions:` application delegate method. + + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:CognitoRegionType + identityPoolId:CognitoIdentityPoolId]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:DefaultServiceRegionType + credentialsProvider:credentialsProvider]; + AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration; + +1. Import the appropriate headers for the services you are using. The header file import convention is `@import AWSServiceName;`, as in the following examples: + + @import AWSS3; + @import AWSDynamoDB; + @import AWSSQS; + @import AWSSNS; + @import AWSCognito; + +1. Make a call to the AWS services. + + AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager]; + AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new]; + uploadRequest.bucket = yourBucket; + uploadRequest.key = yourKey; + uploadRequest.body = yourDataURL; + uploadRequest.contentLength = [NSNumber numberWithUnsignedLongLong:fileSize]; + + [[transferManager upload:uploadRequest] continueWithBlock:^id(AWSTask *task) { + // Do something with the response + return nil; + }]; + + **Note**: Most of the service client classes have a singleton method to get a default client. The naming convention is `+ defaultSERVICENAME` (e.g. `+ defaultS3TransferManager` in the above code snippet). This singleton method creates a service client with `defaultServiceConfiguration`, which you set up in step 5, and maintains a strong reference to the client. + +## AWSTask + +With native AWSTask support in the SDK for iOS, you can chain async requests instead of nesting them. It makes the logic cleaner, while keeping the code more readable. Read [Working with AWSTask](http://docs.aws.amazon.com/mobile/sdkforios/developerguide/awstask.html) to learn how to use AWSTask. + +## Logging + +As of version 2.5.4 of this SDK, logging utilizes [CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack), a flexible, fast, open source logging framework. It supports many capabilities including the ability to set logging level per output target, for instance, concise messages logged to the console and verbose messages to a log file. + +CocoaLumberjack logging levels are additive such that when the level is set to verbose, all messages from the levels below verbose are logged. It is also possible to set custom logging to meet your needs. For more information, see [CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack/blob/master/Documentation/CustomLogLevels.md) + +### Changing Log Levels + +**Swift** + + AWSDDLog.sharedInstance().logLevel = .verbose + +The following logging level options are available: + +* `.off` +* `.error` +* `.warning` +* `.info` +* `.debug` +* `.verbose` + +**Objective-C** + + [AWSDDLog sharedInstance].logLevel = AWSDDLogLevelVerbose; + +The following logging level options are available: + +* `AWSDDLogLevelOff` +* `AWSDDLogLevelError` +* `AWSDDLogLevelWarning` +* `AWSDDLogLevelInfo` +* `AWSDDLogLevelDebug` +* `AWSDDLogLevelVerbose` + +We recommend setting the log level to `Off` before publishing to the Apple App Store. + +### Targeting Log Output + +CocoaLumberjack can direct logs to file or used as a framework that integrates with the Xcode console. + +To initialize logging to files, use the following code: + +**Swift** + + let fileLogger: AWSDDFileLogger = AWSDDFileLogger() // File Logger + fileLogger.rollingFrequency = TimeInterval(60*60*24) // 24 hours + fileLogger.logFileManager.maximumNumberOfLogFiles = 7 + AWSDDLog.add(fileLogger) + +**Objective-C** + + AWSDDFileLogger *fileLogger = [[AWSDDFileLogger alloc] init]; // File Logger + fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling + fileLogger.logFileManager.maximumNumberOfLogFiles = 7; + [AWSDDLog addLogger:fileLogger]; + +To initialize logging to your Xcode console, use the following code: + +**Swift** + + AWSDDLog.add(AWSDDTTYLogger.sharedInstance()) // TTY = Xcode console + +**Objective-C** + + [AWSDDLog addLogger:[AWSDDTTYLogger sharedInstance]]; // TTY = Xcode console + +## Sample Apps + +The AWS SDK for iOS includes sample apps that demonstrate common use cases. + +### Cognito Your User Pools Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Objective-C/)) + +This sample demonstrates how sign up and sign in a user to display an authenticated portion of your app. + +### Cognito Sync Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoSync-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoSync-Sample/Objective-C/)) + +This sample demonstrates how to securely manage and sync your mobile app data and create unique identities via login providers including Facebook, Google, and Login with Amazon. + +#### AWS Services Demonstrated: + +* [Amazon Cognito Sync](http://aws.amazon.com/cognito/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +### DynamoDB Object Mapper Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/DynamoDBObjectMapper-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/DynamoDBObjectMapper-Sample/Objective-C/)) + +This sample demonstrates how to insert / update / delete / query items using DynamoDB Object Mapper. + +#### AWS Services Demonstrated: + +* [Amazon DynamoDB](http://aws.amazon.com/dynamodb/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +### S3 Transfer Manager Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/S3TransferManager-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/S3TransferManager-Sample/Objective-C/)) + +This sample demonstrates how to upload / download multiple files simultaneously using S3 Transfer Manager. It also shows how to pause, resume, and cancel file upload / download. + +#### AWS Services Demonstrated: + +* [Amazon S3](http://aws.amazon.com/s3/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +### S3 Transfer Utility Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/S3BackgroundTransfer-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/S3BackgroundTransfer-Sample/Objective-C/)) + +This sample demonstrates how to use the Amazon S3 PreSigned URL Builder to download / upload files in background. + +#### AWS Services Demonstrated: + +* [Amazon S3](http://aws.amazon.com/s3/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + + +### SNS Mobile Push and Mobile Analytics Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/SNS-MobileAnalytics-Sample/Swift/), [Objective-C](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/SNS-MobileAnalytics-Sample/Objective-C/)) + +This sample demonstrates how to set up Amazon SNS Mobile Push and record events using Amazon Mobile Analytics. + +#### AWS Services Demonstrated: + +* [Amazon SNS Mobile Push](http://aws.amazon.com/sns/) +* [Amazon Mobile Analytics](http://aws.amazon.com/mobileanalytics/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +### IoT Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/)) + +This sample demonstrates how to publish and subscribe to data using AWS IoT. + +#### AWS Services Demonstrated: + +* [Amazon AWS IoT](http://aws.amazon.com/iot/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +### IoT Temperature Control Sample ([Swift](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoTTemperatureControl-Sample/Swift/)) + +This sample demonstrates accessing device shadows using Cognito authentication; it works in conjunction with the Temperature Control Example Program in the [AWS IoT JavaScript SDK for Embedded Devices](https://github.com/aws/aws-iot-device-sdk-js). + +#### AWS Services Demonstrated: + +* [Amazon AWS IoT](http://aws.amazon.com/iot/) +* [Amazon Cognito Identity](http://aws.amazon.com/cognito/) + +## Install the Reference Documentation in Xcode + +The AWS Mobile SDK for iOS zip file includes documentation in the DocSets format that you can view within Xcode. The easiest way to install the documentation is to use the Mac OS X terminal. + +1. Open the Mac OS X terminal and go to the directory containing the expanded archive. For example: + + $ cd ~/Downloads/aws-ios-sdk-2.5.0 + + **Note**: Remember to replace 2.5.0 in the example above with the actual version number of the AWS SDK for iOS that you downloaded. + +1. Create a directory called `~/Library/Developer/Shared/Documentation/DocSets`: + + $ mkdir -p ~/Library/Developer/Shared/Documentation/DocSets + +1. Copy (or move) `Documentation/com.amazon.aws.ios.docset` from the SDK installation files to the directory you created in the previous step: + + $ mv Documentation/com.amazon.aws.ios.docset ~/Library/Developer/Shared/Documentation/DocSets/ + +1. If Xcode was running during this procedure, restart Xcode. To browse the documentation, go to **Help**, click **Documentation and API Reference**, and select **AWS Mobile SDK for iOS v2.5.0 Documentation** (where '2.5.0' is the appropriate version number). + +## Talk to Us + +Visit our GitHub [Issues](https://github.com/aws/aws-sdk-ios/issues) to leave feedback and to connect with other users of the SDK. + +## Author + +Amazon Web Services + +## License + +See the **LICENSE** file for more info. diff --git a/ios/Pods/AWSCore/AWSCore/AWSCore.h b/ios/Pods/AWSCore/AWSCore/AWSCore.h new file mode 100644 index 00000000..01fdf45b --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/AWSCore.h @@ -0,0 +1,54 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + +//! Project version number for AWSCore. +FOUNDATION_EXPORT double AWSCoreVersionNumber; + +//! Project version string for AWSCore. +FOUNDATION_EXPORT const unsigned char AWSCoreVersionString[]; + +#import "AWSCocoaLumberjack.h" + +#import "AWSServiceEnum.h" +#import "AWSService.h" +#import "AWSCredentialsProvider.h" +#import "AWSIdentityProvider.h" +#import "AWSModel.h" +#import "AWSNetworking.h" +#import "AWSCategory.h" +#import "AWSLogging.h" +#import "AWSClientContext.h" +#import "AWSSynchronizedMutableDictionary.h" +#import "AWSSerialization.h" +#import "AWSURLRequestSerialization.h" +#import "AWSURLResponseSerialization.h" +#import "AWSURLSessionManager.h" +#import "AWSSignature.h" +#import "AWSURLRequestRetryHandler.h" +#import "AWSValidation.h" +#import "AWSInfo.h" + +#import "AWSBolts.h" +#import "AWSGZIP.h" +#import "AWSFMDB.h" +#import "AWSKSReachability.h" +#import "AWSTMCache.h" +#import "AWSUICKeyChainStore.h" + + +#import "AWSSTS.h" +#import "AWSCognitoIdentity.h" diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.h b/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.h new file mode 100644 index 00000000..c42a21d4 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.h @@ -0,0 +1,263 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import "AWSServiceEnum.h" +#import "AWSIdentityProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const AWSCognitoCredentialsProviderErrorDomain; +typedef NS_ENUM(NSInteger, AWSCognitoCredentialsProviderErrorType) { + AWSCognitoCredentialsProviderErrorUnknown, + AWSCognitoCredentialsProviderIdentityIdIsNil, + AWSCognitoCredentialsProviderInvalidConfiguration, + AWSCognitoCredentialsProviderInvalidCognitoIdentityToken, + AWSCognitoCredentialsProviderCredentialsRefreshTimeout, +}; + +@class AWSTask<__covariant ResultType>; + +/** + An AWS credentials container class. + */ +@interface AWSCredentials : NSObject + +/** + Access Key component of credentials. + */ +@property (nonatomic, strong, readonly) NSString *accessKey; + +/** + Secret Access Key component of credentials. + */ +@property (nonatomic, strong, readonly) NSString *secretKey; + +/** + Session Token component of credentials. + */ +@property (nonatomic, strong, readonly, nullable) NSString *sessionKey; + +/** + Date at which these credentials will expire. + */ +@property (nonatomic, strong, readonly, nullable) NSDate *expiration; + +/** + Initiates an AWS credentials object. + + @param accessKey An AWS Access key. + @param secretKey An AWS Secret key. + @param sessionKey An AWS Session key. + @param expiration The expiration date of the temporary AWS credentials. + + @return An AWS credentials object. + */ +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey + sessionKey:(nullable NSString *)sessionKey + expiration:(nullable NSDate *)expiration; + +@end + +/** + The AWS credentials provider protocol used to provide credentials to the SDK in order to make calls to the AWS services. + */ +@protocol AWSCredentialsProvider + +/** + Asynchronously returns a valid AWS credentials or an error object if it cannot retrieve valid credentials. It should cache valid credentials as much as possible and refresh them when they are invalid. + + @return A valid AWS credentials or an error object describing the error. + */ +- (AWSTask *)credentials; + +/** + Invalidates the cached temporary AWS credentials. If the credentials provider does not cache temporary credentials, this operation is a no-op. + */ +- (void)invalidateCachedTemporaryCredentials; + +@end + +/** + @warning This credentials provider is intended only for testing purposes. + We strongly discourage embedding AWS credentials in your production apps because they can be easily extracted and abused. Consider using `AWSCognitoCredentialsProvider`. + */ +@interface AWSStaticCredentialsProvider : NSObject + +/** + Instantiates a static credentials provider. + + @param accessKey An AWS Access key. + @param secretKey An AWS Secret key. + + @return An AWS credentials object. + */ +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey; + +@end + +/** + @warning This credentials provider is intended only for testing purposes. + We strongly discourage embedding AWS credentials in your production apps because they can be easily extracted and abused. Consider using `AWSCognitoCredentialsProvider`. + Simple session credentials with keys and session token. + */ +@interface AWSBasicSessionCredentialsProvider: NSObject + +/** + Instantiates a static credentials provider. + + @param accessKey An AWS Access key. + @param secretKey An AWS Secret key. + @param sessionToken The session token for this session. + @return An AWS credentials object. + */ +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey + sessionToken:(NSString *)sessionToken; + +@end + +@interface AWSAnonymousCredentialsProvider : NSObject + +@end + +/** + A credentials provider that uses AWS STS web identity federation. + */ +@interface AWSWebIdentityCredentialsProvider : NSObject + +@property (nonatomic, strong) NSString *webIdentityToken; +@property (nonatomic, strong) NSString *roleArn; +@property (nonatomic, strong) NSString *roleSessionName; +@property (nonatomic, strong) NSString *providerId; + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + providerId:(nullable NSString *)providerId + roleArn:(NSString *)roleArn + roleSessionName:(NSString *)roleSessionName + webIdentityToken:(NSString *)webIdentityToken; + +@end + +/** + An AWSCredentialsProvider that uses Amazon Cognito to fetch temporary credentials tied to an identity. + + To learn more about Amazon Cognito, please visit https://aws.amazon.com/cognito. + + There are 3 different flows supported by this credentials provider, see factory and init methods for choosing the right one for your use case: + + 1. Enhanced flow: Uses Cognito for all operations and only requires an identity pool id to initialize. + 2. Basic flow: Uses Cognito + STS and requires identity pool plus IAM roles + 3. Developer authenticated identities: Uses your own AWSCognitoCredentialsProviderHelper to establish identity + + Cognito (and optionally STS) to establish credentials. + */ +@interface AWSCognitoCredentialsProvider : NSObject + +/** + The identityProvider which is responsible for establishing the identity id and (optionally) the open id token for use in the Amazon Cognito authflow. + */ +@property (nonatomic, strong, readonly) id identityProvider; + +/** + The identity id associated with this provider. This value will be fetched from the keychain at startup. If you do not want to reuse the existing identity id, you must call the clearKeychain method. + */ +@property (nonatomic, strong, readonly, nullable) NSString *identityId; + +/** + The identity pool id associated with this provider. Also used to create a namedspaced keychain area to store identity id and credentials. + */ +@property (nonatomic, strong, readonly) NSString *identityPoolId; + +/** + Initializer for credentials provider with enhanced authentication flow. This is the recommended constructor for first time Amazon Cognito developers. Will create an instance of `AWSEnhancedCognitoIdentityProvider`. + + @param regionType The region in which your identity pool exists. + @param identityPoolId The identity pool id for this provider. Value is used to communicate with Amazon Cognito as well as namespace values stored in the keychain. + */ +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId; + +/** + Initializer for credentials provider with enhanced authentication flow. This is the recommended method for first time Amazon Cognito developers. Will create an instance of `AWSEnhancedCognitoIdentityProvider`. + + @param regionType The region in which your identity pool exists. + @param identityPoolId The identity pool id for this provider. Value is used to communicate with Amazon Cognito as well as namespace values stored in the keychain. + @param identityProviderManager An object that conforms to the `AWSIdentityProviderManager` protocol. It should return a valid `login` dictionary when requested. Can be nil if identity is unauthenticated. + */ +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + identityProviderManager:(nullable id)identityProviderManager; + +/** + Initializer for credentials provider with pre-created `AWSCognitoCredentialsProviderHelper`. Use this method when using developer authenticated identities. + + @param regionType The region in which your identity pool exists. + @param identityProvider Implementation of AWSCognitoCredentialsProviderHelper which is responsible for acquiring identity id and (optionally) OpenId Connect token. + */ +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityProvider:(id)identityProvider; + +/** + Initializer for credentials provider with pre-created `AWSCognitoCredentialsProviderHelper`. Only use this method if you need to set your IAM roles client side and use developer authenticated identities + + @param regionType The region in which your identity pool exists. + @param unauthRoleArn The role ARN to use when getting credentials for unauthenticated identities. Provider will check the `isAuthenticated` property of the identity provider to determine which role to use. Can be nil if unauthenticated identities are not supported or if using enhanced authentication flow. + @param authRoleArn The role ARN to use when getting credentials for authenticated identities. Provider will check the `isAuthenticated` property of the identity provider to determine which role to use. Can be nil if authenticated identities are not supported or if using enhanced authentication flow. + @param identityProvider Implementation of AWSCognitoCredentialsProviderHelper which is responsible for acquiring identity id and (optionally) OpenId Connect token. + */ +- (instancetype)initWithRegionType:(AWSRegionType)regionType + unauthRoleArn:(nullable NSString *)unauthRoleArn + authRoleArn:(nullable NSString *)authRoleArn + identityProvider:(id)identityProvider; + +/** + Initializer for credentials provider with basic auth flow. Only use this method if you still need to set your IAM roles client side. This method will create an instance of `AWSBasicCognitoIdentityProvider`. + + @param regionType The region in which your identity pool exists. + @param identityPoolId The identity pool id for this provider. Value is used to communicate with Amazon Cognito as well as namespace values stored in the keychain. + @param unauthRoleArn The role ARN to use when getting credentials for unauthenticated identities. Provider will check the `isAuthenticated` property of the identity provider to determine which role to use. Can be nil if unauthenticated identities are not supported. + @param authRoleArn The role ARN to use when getting credentials for authenticated identities. Provider will check the `isAuthenticated` property of the identity provider to determine which role to use. Can be nil if authenticated identities are not supported. + @param identityProviderManager An object that conforms to the `AWSIdentityProviderManager` protocol. It should return a valid `login` dictionary when requested. Can be nil if identity is unauthenticated. + */ +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + unauthRoleArn:(nullable NSString *)unauthRoleArn + authRoleArn:(nullable NSString *)authRoleArn + identityProviderManager:(nullable id)identityProviderManager; + +/** + Get/retrieve the identity id for this provider. If an identity id is already set on this provider, no remote call is made and the identity will be returned as a result of the AWSTask (the identityId is also available as a property). If no identityId is set on this provider, one will be retrieved from the service. + + @return AWSTask + */ +- (AWSTask *)getIdentityId; + +/** + Clear ALL saved values for this provider (identityId, credentials, logins). + */ +- (void)clearKeychain; + +/** + Clear the cached AWS credentials for this provider. + */ +- (void)clearCredentials; + +- (void)setIdentityProviderManagerOnce:(id)identityProviderManager; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.m b/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.m new file mode 100644 index 00000000..7d01cc5b --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSCredentialsProvider.m @@ -0,0 +1,728 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCredentialsProvider.h" +#import "AWSCognitoIdentity.h" +#import "AWSSTS.h" +#import "AWSUICKeyChainStore.h" +#import "AWSCocoaLumberjack.h" +#import "AWSBolts.h" + +NSString *const AWSCognitoCredentialsProviderErrorDomain = @"com.amazonaws.AWSCognitoCredentialsProviderErrorDomain"; + +static NSString *const AWSCredentialsProviderKeychainAccessKeyId = @"accessKey"; +static NSString *const AWSCredentialsProviderKeychainSecretAccessKey = @"secretKey"; +static NSString *const AWSCredentialsProviderKeychainSessionToken = @"sessionKey"; +static NSString *const AWSCredentialsProviderKeychainExpiration = @"expiration"; +static NSString *const AWSCredentialsProviderKeychainIdentityId = @"identityId"; + +@interface AWSCognitoIdentity() + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration; + +@end + +@interface AWSSTS() + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration; + +@end + +@interface AWSAbstractCognitoCredentialsProviderHelper() + +@property (nonatomic, strong) id identityProviderManager; + +@end + +@implementation AWSCredentials + +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey + sessionKey:(NSString *)sessionKey + expiration:(NSDate *)expiration { + if (self = [super init]) { + _accessKey = accessKey; + _secretKey = secretKey; + _sessionKey = sessionKey; + _expiration = expiration; + } + + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"{\nAWSCredentials\nAccessKey: %@\nSecretKey: %@\nSessionKey: %@\nExpiration: %@\n}", + self.accessKey, + self.secretKey, + self.sessionKey, + self.expiration]; +} + +@end + +@interface AWSStaticCredentialsProvider() + +@property (nonatomic, strong) AWSCredentials *internalCredentials; + +@end + +@implementation AWSStaticCredentialsProvider + +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey { + if (self = [super init]) { + _internalCredentials = [[AWSCredentials alloc] initWithAccessKey:accessKey + secretKey:secretKey + sessionKey:nil + expiration:nil]; + } + return self; +} + +- (AWSTask *)credentials { + return [AWSTask taskWithResult:self.internalCredentials]; +} + +- (void)invalidateCachedTemporaryCredentials { + // No-op +} + +@end + +@interface AWSBasicSessionCredentialsProvider() + +@property (nonatomic, strong) AWSCredentials *internalCredentials; + +@end + +@implementation AWSBasicSessionCredentialsProvider + +- (instancetype)initWithAccessKey:(NSString *)accessKey + secretKey:(NSString *)secretKey + sessionToken:(NSString *)sessionToken { + if (self = [super init]) { + _internalCredentials = [[AWSCredentials alloc] initWithAccessKey:accessKey + secretKey:secretKey + sessionKey:sessionToken + expiration:nil]; + } + return self; +} + +- (AWSTask *)credentials { + return [AWSTask taskWithResult:self.internalCredentials]; +} + +- (void)invalidateCachedTemporaryCredentials { + // No-op +} + +@end + +@implementation AWSAnonymousCredentialsProvider + +- (AWSTask *)credentials { + return [AWSTask taskWithResult:nil]; +} + +- (void)invalidateCachedTemporaryCredentials { + // No-op +} + +@end + +@interface AWSWebIdentityCredentialsProvider() + +@property (nonatomic, strong) AWSSTS *sts; +@property (nonatomic, strong) AWSUICKeyChainStore *keychain; +@property (nonatomic, strong) AWSCredentials *internalCredentials; + +@end + +@implementation AWSWebIdentityCredentialsProvider + +@synthesize internalCredentials = _internalCredentials; + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + providerId:(NSString *)providerId + roleArn:(NSString *)roleArn + roleSessionName:(NSString *)roleSessionName + webIdentityToken:(NSString *)webIdentityToken { + if (self = [super init]) { + _keychain = [AWSUICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@.%@", providerId, webIdentityToken, roleArn]]; + _providerId = providerId; + _roleArn = roleArn; + _roleSessionName = roleSessionName; + _webIdentityToken = webIdentityToken; + + AWSAnonymousCredentialsProvider *credentialsProvider = [AWSAnonymousCredentialsProvider new]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:regionType + credentialsProvider:credentialsProvider]; + _sts = [[AWSSTS alloc] initWithConfiguration:configuration]; + } + + return self; +} + +#pragma mark - AWSCredentialsProvider methods + +- (AWSTask *)credentials { + // Preemptively refresh credentials if any of the following is true: + // 1. accessKey or secretKey is nil. + // 2. the credentials expires within 10 minutes. + if (self.internalCredentials.accessKey + && self.internalCredentials.secretKey + && [self.internalCredentials.expiration compare:[NSDate dateWithTimeIntervalSinceNow:10 * 60]] == NSOrderedDescending) { + + return [AWSTask taskWithResult:self.internalCredentials]; + } + + // request new credentials + AWSSTSAssumeRoleWithWebIdentityRequest *webIdentityRequest = [AWSSTSAssumeRoleWithWebIdentityRequest new]; + webIdentityRequest.providerId = self.providerId; + webIdentityRequest.roleArn = self.roleArn; + webIdentityRequest.roleSessionName = self.roleSessionName; + webIdentityRequest.webIdentityToken = self.webIdentityToken; + + return [[self.sts assumeRoleWithWebIdentity:webIdentityRequest] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + if (task.result) { + AWSSTSAssumeRoleWithWebIdentityResponse *wifResponse = task.result; + self.internalCredentials = [[AWSCredentials alloc] initWithAccessKey:wifResponse.credentials.accessKeyId + secretKey:wifResponse.credentials.secretAccessKey + sessionKey:wifResponse.credentials.sessionToken + expiration:wifResponse.credentials.expiration]; + + return [AWSTask taskWithResult:self.internalCredentials]; + } else { + // reset the values for the credentials + [self invalidateCachedTemporaryCredentials]; + } + + return task; + }]; +} + +- (void)invalidateCachedTemporaryCredentials { + self.internalCredentials = nil; +} + +#pragma mark - + +- (AWSCredentials *)internalCredentials { + if (_internalCredentials) { + return _internalCredentials; + } + + if (self.keychain[AWSCredentialsProviderKeychainAccessKeyId] + && self.keychain[AWSCredentialsProviderKeychainSecretAccessKey]) { + NSString *expirationString = self.keychain[AWSCredentialsProviderKeychainExpiration]; + NSDate *expiration = nil; + if (expirationString) { + expiration = [NSDate dateWithTimeIntervalSince1970:[expirationString doubleValue]]; + } + AWSCredentials *credentials = [[AWSCredentials alloc] initWithAccessKey:self.keychain[AWSCredentialsProviderKeychainAccessKeyId] + secretKey:self.keychain[AWSCredentialsProviderKeychainSecretAccessKey] + sessionKey:self.keychain[AWSCredentialsProviderKeychainSessionToken] + expiration:expiration]; + + return credentials; + } + + return nil; +} + +- (void)setInternalCredentials:(AWSCredentials *)internalCredentials { + _internalCredentials = internalCredentials; + + self.keychain[AWSCredentialsProviderKeychainAccessKeyId] = internalCredentials.accessKey; + self.keychain[AWSCredentialsProviderKeychainSecretAccessKey] = internalCredentials.secretKey; + self.keychain[AWSCredentialsProviderKeychainSessionToken] = internalCredentials.sessionKey; + if (internalCredentials.expiration) { + self.keychain[AWSCredentialsProviderKeychainExpiration] = [NSString stringWithFormat:@"%f", [internalCredentials.expiration timeIntervalSince1970]]; + } else { + self.keychain[AWSCredentialsProviderKeychainExpiration] = nil; + } +} + +@end + +@interface AWSCognitoCredentialsProvider() + +@property (nonatomic, strong) NSString *authRoleArn; +@property (nonatomic, strong) NSString *unAuthRoleArn; +@property (nonatomic, strong) AWSSTS *sts; +@property (nonatomic, strong) AWSCognitoIdentity *cognitoIdentity; +@property (nonatomic, strong) AWSUICKeyChainStore *keychain; +@property (nonatomic, strong) AWSExecutor *refreshExecutor; +@property (nonatomic, strong) dispatch_semaphore_t semaphore; +@property (atomic, assign) BOOL useEnhancedFlow; +@property (nonatomic, strong) AWSCredentials *internalCredentials; +@property (atomic, assign, getter=isRefreshingCredentials) BOOL refreshingCredentials; +@property (nonatomic, strong) NSDictionary *cachedLogins; +@property (atomic, assign) BOOL hasClearedIdentityId; + +@end + +@implementation AWSCognitoCredentialsProvider + +@synthesize internalCredentials = _internalCredentials; + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId { + if (self = [super init]) { + AWSCognitoCredentialsProviderHelper *identityProvider = [[AWSCognitoCredentialsProviderHelper alloc] initWithRegionType:regionType + identityPoolId:identityPoolId + useEnhancedFlow:YES + identityProviderManager:nil]; + [self setUpWithRegionType:regionType + identityProvider:identityProvider + unauthRoleArn:nil + authRoleArn:nil]; + } + + return self; +} + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + identityProviderManager:(nullable id)identityProviderManager { + if (self = [super init]) { + AWSCognitoCredentialsProviderHelper *identityProvider = [[AWSCognitoCredentialsProviderHelper alloc] initWithRegionType:regionType + identityPoolId:identityPoolId + useEnhancedFlow:YES + identityProviderManager:identityProviderManager]; + [self setUpWithRegionType:regionType + identityProvider:identityProvider + unauthRoleArn:nil + authRoleArn:nil]; + } + + return self; +} + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityProvider:(id)identityProvider { + if (self = [super init]) { + [self setUpWithRegionType:regionType + identityProvider:identityProvider + unauthRoleArn:nil + authRoleArn:nil]; + } + + return self; +} + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + unauthRoleArn:(NSString *)unauthRoleArn + authRoleArn:(NSString *)authRoleArn + identityProvider:(id)identityProvider { + if (self = [super init]) { + [self setUpWithRegionType:regionType + identityProvider:identityProvider + unauthRoleArn:unauthRoleArn + authRoleArn:authRoleArn]; + } + + return self; +} + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + unauthRoleArn:(nullable NSString *)unauthRoleArn + authRoleArn:(nullable NSString *)authRoleArn + identityProviderManager:(nullable id)identityProviderManager { + if (self = [super init]) { + AWSCognitoCredentialsProviderHelper *identityProvider = [[AWSCognitoCredentialsProviderHelper alloc] initWithRegionType:regionType + identityPoolId:identityPoolId + useEnhancedFlow:NO + identityProviderManager:identityProviderManager]; + [self setUpWithRegionType:regionType + identityProvider:identityProvider + unauthRoleArn:unauthRoleArn + authRoleArn:authRoleArn]; + } + + return self; +} + +- (void)setUpWithRegionType:(AWSRegionType)regionType + identityProvider:(id)identityProvider + unauthRoleArn:(NSString *)unauthRoleArn + authRoleArn:(NSString *)authRoleArn { + _refreshExecutor = [AWSExecutor executorWithOperationQueue:[NSOperationQueue new]]; + _refreshingCredentials = NO; + _semaphore = dispatch_semaphore_create(0); + + _identityProvider = identityProvider; + _unAuthRoleArn = unauthRoleArn; + _authRoleArn = authRoleArn; + _useEnhancedFlow = !unauthRoleArn && !authRoleArn; + + // initialize keychain - name spaced by app bundle and identity pool id + _keychain = [AWSUICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@.%@", [NSBundle mainBundle].bundleIdentifier, [AWSCognitoCredentialsProvider class], identityProvider.identityPoolId]]; + + // If the identity provider has an identity id, use it + if (identityProvider.identityId) { + _keychain[AWSCredentialsProviderKeychainIdentityId] = identityProvider.identityId; + } + // Otherwise push whatever is in the keychain down to the identity provider + else { + identityProvider.identityId = _keychain[AWSCredentialsProviderKeychainIdentityId]; + } + + AWSAnonymousCredentialsProvider *credentialsProvider = [AWSAnonymousCredentialsProvider new]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:regionType + credentialsProvider:credentialsProvider]; + + _cognitoIdentity = [[AWSCognitoIdentity alloc] initWithConfiguration:configuration]; + + if (!_useEnhancedFlow) { + _sts = [[AWSSTS alloc] initWithConfiguration:configuration]; + } +} + +- (AWSTask *)getCredentialsWithSTS:(NSDictionary *)logins + authenticated:(BOOL)auth { + NSString *roleArn = self.unAuthRoleArn; + if (auth) { + roleArn = self.authRoleArn; + } + + if (!roleArn) { + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderInvalidConfiguration + userInfo:@{NSLocalizedDescriptionKey: @"Required role ARN is nil"}]]; + } + + if (![logins objectForKey:AWSIdentityProviderAmazonCognitoIdentity]) { + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderInvalidCognitoIdentityToken + userInfo:@{NSLocalizedDescriptionKey: @"Invalid logins dictionary."}]]; + } + + AWSSTSAssumeRoleWithWebIdentityRequest *webIdentityRequest = [AWSSTSAssumeRoleWithWebIdentityRequest new]; + webIdentityRequest.roleArn = roleArn; + webIdentityRequest.webIdentityToken = [logins objectForKey:AWSIdentityProviderAmazonCognitoIdentity]; + webIdentityRequest.roleSessionName = @"iOS-Provider"; + return [[self.sts assumeRoleWithWebIdentity:webIdentityRequest] continueWithBlock:^id(AWSTask *task) { + if (task.result) { + AWSSTSAssumeRoleWithWebIdentityResponse *webIdentityResponse = task.result; + self.internalCredentials = [[AWSCredentials alloc] initWithAccessKey:webIdentityResponse.credentials.accessKeyId + secretKey:webIdentityResponse.credentials.secretAccessKey + sessionKey:webIdentityResponse.credentials.sessionToken + expiration:webIdentityResponse.credentials.expiration]; + + return [AWSTask taskWithResult:self.internalCredentials]; + } else { + // reset the values for the credentials + [self clearCredentials]; + } + + return task; + }]; +} + +- (AWSTask *)getCredentialsWithCognito:(NSDictionary *)logins + authenticated:(BOOL)isAuthenticated + customRoleArn:(NSString *)customRoleArn { + // Grab a reference to our provider in case it changes out from under us + id providerRef = self.identityProvider; + + AWSCognitoIdentityGetCredentialsForIdentityInput *getCredentialsInput = [AWSCognitoIdentityGetCredentialsForIdentityInput new]; + getCredentialsInput.identityId = self.identityId; + getCredentialsInput.logins = logins; + getCredentialsInput.customRoleArn = customRoleArn; + + return [[[self.cognitoIdentity getCredentialsForIdentity:getCredentialsInput] continueWithBlock:^id(AWSTask *task) { + // When an invalid identityId is cached in the keychain for auth, + // we will refresh the identityId and try to get credentials token again. + if (task.error) { + AWSDDLogError(@"GetCredentialsForIdentity failed. Error is [%@]", task.error); + + // If we should reset IdentityId, clears it and retries. + // Otherwise, simply returns the error to the caller. + if (![AWSCognitoCredentialsProvider shouldResetIdentityId:task.error + authenticated:isAuthenticated]) { + return task; + } + + if (self.hasClearedIdentityId) { + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderInvalidConfiguration + userInfo:@{NSLocalizedDescriptionKey : @"GetCredentialsForIdentity keeps failing. Clearing identityId did not help. Please check your Amazon Cognito Identity configuration."}]]; + } + + AWSDDLogDebug(@"Resetting identity Id and calling getIdentityId"); + // if it's auth, reset id and refetch + self.identityId = nil; + providerRef.identityId = nil; + self.hasClearedIdentityId = YES; + + return [[providerRef logins] continueWithSuccessBlock:^id _Nullable(AWSTask *> * _Nonnull task) { + NSDictionary *logins = task.result; + + // This should never happen, but just in case + if (!providerRef.identityId) { + AWSDDLogError(@"In refresh, but identitId is nil."); + AWSDDLogError(@"Result from getIdentityId is %@", task.result); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}]]; + } + self.identityId = providerRef.identityId; + + AWSDDLogDebug(@"Retrying GetCredentialsForIdentity"); + + // retry get credentials + AWSCognitoIdentityGetCredentialsForIdentityInput *getCredentialsRetry = [AWSCognitoIdentityGetCredentialsForIdentityInput new]; + getCredentialsRetry.identityId = self.identityId; + getCredentialsRetry.logins = logins; + getCredentialsRetry.customRoleArn = customRoleArn; + + return [self.cognitoIdentity getCredentialsForIdentity:getCredentialsRetry]; + }]; + } + return task; + }] continueWithSuccessBlock:^id(AWSTask *task) { + AWSCognitoIdentityGetCredentialsForIdentityResponse *getCredentialsResponse = task.result; + self.internalCredentials = [[AWSCredentials alloc] initWithAccessKey:getCredentialsResponse.credentials.accessKeyId + secretKey:getCredentialsResponse.credentials.secretKey + sessionKey:getCredentialsResponse.credentials.sessionToken + expiration:getCredentialsResponse.credentials.expiration]; + + NSString *identityIdFromResponse = getCredentialsResponse.identityId; + + // This should never happen, but just in case + if (!identityIdFromResponse) { + AWSDDLogError(@"identityId from getCredentialsForIdentity is nil"); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}] + ]; + } + + if (![self.identityId isEqualToString:identityIdFromResponse]) { + self.identityId = identityIdFromResponse; + providerRef.identityId = identityIdFromResponse; + } + + return [AWSTask taskWithResult:self.internalCredentials]; + }]; +} + +#pragma mark - AWSCredentialsProvider methods + +- (AWSTask *)credentials { + // Returns cached credentials when all of the following conditions are true: + // 1. The cached credentials are not nil. + // 2. The credentials do not expire within 10 minutes. + if (self.internalCredentials + && [self.internalCredentials.expiration compare:[NSDate dateWithTimeIntervalSinceNow:10 * 60]] == NSOrderedDescending) { + return [AWSTask taskWithResult:self.internalCredentials]; + } + + id providerRef = self.identityProvider; + return [[[providerRef logins] continueWithExecutor:self.refreshExecutor withSuccessBlock:^id _Nullable(AWSTask *> * _Nonnull task) { + NSDictionary *logins = task.result; + + AWSTask * getIdentityIdTask = nil; + + if(!providerRef.identityId){ + getIdentityIdTask = [self getIdentityId]; + }else { + self.identityId = providerRef.identityId; + getIdentityIdTask = [AWSTask taskWithResult:nil]; + } + + return [getIdentityIdTask continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + // Refreshes the credentials if any of the following is true: + // 1. The cached logins are different from the one the identity provider provided. + // 2. The cached credentials is nil. + // 3. The credentials expire within 10 minutes. + if ((!self.cachedLogins || [self.cachedLogins isEqualToDictionary:logins]) + && self.internalCredentials + && [self.internalCredentials.expiration compare:[NSDate dateWithTimeIntervalSinceNow:10 * 60]] == NSOrderedDescending) { + return [AWSTask taskWithResult:self.internalCredentials]; + } + + if (self.isRefreshingCredentials) { + // Waits up to 60 seconds for the Google SDK to refresh a token. + if (dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC)) != 0) { + NSError *error = [NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderCredentialsRefreshTimeout + userInfo:nil]; + return [AWSTask taskWithError:error]; + } + } + + if ((!self.cachedLogins || [self.cachedLogins isEqualToDictionary:logins]) + && self.internalCredentials + && [self.internalCredentials.expiration compare:[NSDate dateWithTimeIntervalSinceNow:10 * 60]] == NSOrderedDescending) { + return [AWSTask taskWithResult:self.internalCredentials]; + } + + self.refreshingCredentials = YES; + self.cachedLogins = logins; + + if (self.useEnhancedFlow) { + NSString * customRoleArn = nil; + if([providerRef.identityProviderManager respondsToSelector:@selector(customRoleArn)]){ + customRoleArn = providerRef.identityProviderManager.customRoleArn; + } + return [self getCredentialsWithCognito:logins + authenticated:[providerRef isAuthenticated] + customRoleArn:customRoleArn]; + } else { + return [self getCredentialsWithSTS:logins + authenticated:[providerRef isAuthenticated]]; + } + + }]; + }] continueWithBlock:^id(AWSTask *task) { + if (task.error) { + AWSDDLogError(@"Unable to refresh. Error is [%@]", task.error); + } + + self.refreshingCredentials = NO; + dispatch_semaphore_signal(self.semaphore); + + return task; + }]; +} + +- (void)invalidateCachedTemporaryCredentials { + self.internalCredentials = nil; +} + +#pragma mark - + +- (AWSTask *)getIdentityId { + // Grab a reference to our provider in case it changes out from under us + id providerRef = self.identityProvider; + + return [[providerRef getIdentityId] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSString *identityId = task.result; + + // This should never happen, but just in case + if (!identityId) { + AWSDDLogError(@"In refresh, but identityId is nil."); + AWSDDLogError(@"Result from getIdentityId is %@", task.result); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderIdentityIdIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}] + ]; + } + + self.identityId = identityId; + + return task; + }]; +} + +- (void)clearKeychain { + [self.identityProvider clear]; + self.identityId = nil; + [self clearCredentials]; +} + +- (void)clearCredentials { + [self invalidateCachedTemporaryCredentials]; +} + +- (void)setIdentityProviderManagerOnce:(id)identityProviderManager { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AWSCognitoCredentialsProviderHelper *cognitoIdentityProvider = self.identityProvider; + cognitoIdentityProvider.identityProviderManager = identityProviderManager; + }); +} + +- (void)setIdentityProvider:(id)identityProvider { + _identityProvider = identityProvider; + [self clearCredentials]; +} + +- (NSString *)identityPoolId { + return self.identityProvider.identityPoolId; +} + ++ (BOOL)shouldResetIdentityId:(NSError *)error + authenticated:(BOOL)isAuthenticated { + BOOL shouldResetIdentityId = NO; + if ([error.domain isEqualToString:AWSCognitoIdentityErrorDomain]) { + if (error.code == AWSCognitoIdentityErrorResourceNotFound) { + shouldResetIdentityId = isAuthenticated; + } + if (error.code == AWSCognitoIdentityErrorUnknown) { + NSString *errorMessage = [error.userInfo objectForKey:@"__type"]; + shouldResetIdentityId = isAuthenticated || [errorMessage isEqualToString:@"ValidationException"]; + } + if (error.code == AWSCognitoIdentityErrorNotAuthorized) { + shouldResetIdentityId = YES; + } + } + return shouldResetIdentityId; +} + +#pragma mark - Getters/setters + +- (NSString *)identityId { + NSString *identityId = self.identityProvider.identityId; + if (identityId) { + return identityId; + } + return [self.keychain stringForKey:AWSCredentialsProviderKeychainIdentityId]; +} + +- (void)setIdentityId:(NSString *)identityId { + self.keychain[AWSCredentialsProviderKeychainIdentityId] = identityId; +} + +- (AWSCredentials *)internalCredentials { + if (_internalCredentials) { + return _internalCredentials; + } + + if (self.keychain[AWSCredentialsProviderKeychainAccessKeyId] + && self.keychain[AWSCredentialsProviderKeychainSecretAccessKey]) { + NSString *expirationString = self.keychain[AWSCredentialsProviderKeychainExpiration]; + NSDate *expiration = nil; + if (expirationString) { + expiration = [NSDate dateWithTimeIntervalSince1970:[expirationString doubleValue]]; + } + AWSCredentials *credentials = [[AWSCredentials alloc] initWithAccessKey:self.keychain[AWSCredentialsProviderKeychainAccessKeyId] + secretKey:self.keychain[AWSCredentialsProviderKeychainSecretAccessKey] + sessionKey:self.keychain[AWSCredentialsProviderKeychainSessionToken] + expiration:expiration]; + return credentials; + } + + return nil; +} + +- (void)setInternalCredentials:(AWSCredentials *)internalCredentials { + _internalCredentials = internalCredentials; + + self.keychain[AWSCredentialsProviderKeychainAccessKeyId] = internalCredentials.accessKey; + self.keychain[AWSCredentialsProviderKeychainSecretAccessKey] = internalCredentials.secretKey; + self.keychain[AWSCredentialsProviderKeychainSessionToken] = internalCredentials.sessionKey; + if (internalCredentials.expiration) { + self.keychain[AWSCredentialsProviderKeychainExpiration] = [NSString stringWithFormat:@"%f", [internalCredentials.expiration timeIntervalSince1970]]; + } else { + self.keychain[AWSCredentialsProviderKeychainExpiration] = nil; + } +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.h b/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.h new file mode 100644 index 00000000..8a42eb98 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.h @@ -0,0 +1,147 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import "AWSServiceEnum.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const AWSCognitoIdentityIdChangedNotification; +FOUNDATION_EXPORT NSString *const AWSCognitoNotificationPreviousId; +FOUNDATION_EXPORT NSString *const AWSCognitoNotificationNewId; + +FOUNDATION_EXPORT NSString *const AWSIdentityProviderDigits; +FOUNDATION_EXPORT NSString *const AWSIdentityProviderFacebook; +FOUNDATION_EXPORT NSString *const AWSIdentityProviderGoogle; +FOUNDATION_EXPORT NSString *const AWSIdentityProviderLoginWithAmazon; +FOUNDATION_EXPORT NSString *const AWSIdentityProviderTwitter; + +FOUNDATION_EXPORT NSString *const AWSIdentityProviderAmazonCognitoIdentity; + +FOUNDATION_EXPORT NSString *const AWSCognitoCredentialsProviderHelperErrorDomain; +typedef NS_ENUM(NSInteger, AWSCognitoCredentialsProviderHelperErrorType) { + AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil, + AWSCognitoCredentialsProviderHelperErrorTypeTokenRefreshTimeout, +}; + +@class AWSTask<__covariant ResultType>; + +/** + AWSIdentityProvider provides an interface for acquiring an identity token from a provider. + */ +@protocol AWSIdentityProvider + +/** + The name of the identity provider. e.g. graph.facebook.com. + */ +@property (nonatomic, readonly) NSString *identityProviderName; + +/** + Returns the token associated with this provider. If the token is cached and invalid, should refresh and return the valid token. + */ +- (AWSTask *)token; + +@end + +/** + `AWSIdentityProviderManager` provides an interface for creating the `logins` dictionary for Amazon Cognito Identity. + */ +@protocol AWSIdentityProviderManager + +/** + Each entry in logins represents a single login with an identity provider. The key is the domain of the login provider (e.g. 'graph.facebook.com') and the value is the OAuth/OpenId Connect token that results from an authentication with that login provider. + */ +- (AWSTask *> *)logins; + +@optional +/** + * If the token contains the role arn and there are multiple roles, return the custom role to assume. This is currently only supported for SAML identity providers. + */ +@property (nonatomic, readonly) NSString *customRoleArn; + +@end + +/** + AWSCognitoCredentialsProviderHelper provides a Cognito specific identity provider. Cognito Identity providers are associated with an identity pool. If the identity pool supports authenticated access, multiple logins may be added to link to the Cognito identity. + */ +@protocol AWSCognitoCredentialsProviderHelper + +/** + The identity pool for this provider. Used to when making calls to the Amazon Cognito service + */ +@property (nonatomic, strong, readonly) NSString *identityPoolId; + +/** + The identity id as determined by the Amazon Cognito service + */ +@property (nonatomic, strong, nullable) NSString *identityId; + +/** + */ +@property (nonatomic, strong, readonly, nullable) id identityProviderManager; + +/** + Get/retrieve the identity id for this provider. If an identity id is already set on this provider, no remote call is made and the identity will be returned as a result of the AWSTask (the identityId is also available as a property). If no identityId is set on this provider, one will be retrieved from the service. + */ +- (AWSTask *)getIdentityId; + +/** + Is this provider considered 'authenticated'. By default, only returns YES if logins is set. + */ +- (BOOL)isAuthenticated; + +/** + Clear saved values for identityId, token, and logins. + */ +- (void)clear; + +@end + +/** + An abstract implementation of the AWSCognitoCredentialsProviderHelper. + */ +@interface AWSAbstractCognitoCredentialsProviderHelper : NSObject + +/** + The identity pool for this provider. Used to when making calls to the Amazon Cognito service + */ +@property (nonatomic, strong, readonly) NSString *identityPoolId; + +/** + The identity id as determined by the Amazon Cognito service + */ +@property (nonatomic, strong, nullable) NSString *identityId; + +/** + The identity provider manager that asynchronously returns `logins`. + */ +@property (nonatomic, strong, readonly, nullable) id identityProviderManager; + +@end + +/** + An abstract implementation of the AWSCognitoCredentialsProviderHelper. Developers should extend this class when they want to implement developer authenticated identities and want to support the basic Amazon Cognito authflow in the same application. + */ +@interface AWSCognitoCredentialsProviderHelper : AWSAbstractCognitoCredentialsProviderHelper + +@property (nonatomic, assign) BOOL useEnhancedFlow; + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + useEnhancedFlow:(BOOL)useEnhancedFlow + identityProviderManager:(nullable id)identityProviderManager; +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.m b/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.m new file mode 100644 index 00000000..58e62327 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSIdentityProvider.m @@ -0,0 +1,334 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// +#import "AWSCore.h" +#import "AWSIdentityProvider.h" +#import "AWSBolts.h" + +NSString *const AWSCognitoIdentityIdChangedNotification = @"com.amazonaws.services.cognitoidentity.AWSCognitoIdentityIdChangedNotification"; +NSString *const AWSCognitoCredentialsProviderHelperErrorDomain = @"com.amazonaws.service.cognitoidentity.AWSCognitoCredentialsProviderHelper"; +NSString *const AWSCognitoNotificationPreviousId = @"PREVID"; +NSString *const AWSCognitoNotificationNewId = @"NEWID"; + +NSString *const AWSIdentityProviderDigits = @"www.digits.com"; +NSString *const AWSIdentityProviderFacebook = @"graph.facebook.com"; +NSString *const AWSIdentityProviderGoogle = @"accounts.google.com"; +NSString *const AWSIdentityProviderLoginWithAmazon = @"www.amazon.com"; +NSString *const AWSIdentityProviderTwitter = @"api.twitter.com"; + +NSString *const AWSIdentityProviderAmazonCognitoIdentity = @"cognito-identity.amazonaws.com"; + +@interface AWSCognitoCredentialsProvider() + ++ (BOOL)shouldResetIdentityId:(NSError *)error + authenticated:(BOOL)isAuthenticated; + +@end + +@interface AWSAbstractCognitoCredentialsProviderHelper() + +@property (nonatomic, strong) id identityProviderManager; +@property (nonatomic, strong) NSString *identityPoolId; +@property (nonatomic, strong) NSDictionary *cachedLogins; + +@end + +@interface AWSCognitoIdentity() + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration; + +@end + +@implementation AWSAbstractCognitoCredentialsProviderHelper + +#pragma mark - AWSIdentityProvider + +// Sub classes should override this. +- (NSString *)identityProviderName { + return @"AWSAbstractCognitoCredentialsProviderHelper"; +} + +// Sub classes should override this. +- (AWSTask *)token { + return [AWSTask taskWithResult:nil]; +} + +#pragma mark - AWSIdentityProviderManager + +// Sub classes should override this. +- (AWSTask *> *)logins { + return [AWSTask taskWithResult:nil]; +} + +#pragma mark - + +// stub class that should be overriden +- (AWSTask *)getIdentityId { + return [AWSTask taskWithResult:self.identityId]; +} + +- (void)clear { + self.identityId = nil; + self.cachedLogins = nil; +} + +- (BOOL)isAuthenticated { + return [self.cachedLogins count] > 0; +} + +- (void)setIdentityId:(NSString *)identityId { + if (identityId && ![identityId isEqualToString:_identityId]) { + [self postIdentityIdChangedNotification:identityId]; + } + _identityId = identityId; +} + +- (void)postIdentityIdChangedNotification:(NSString *)newId { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (self.identityId) { + [userInfo setObject:self.identityId forKey:AWSCognitoNotificationPreviousId]; + } + [userInfo setObject:newId forKey:AWSCognitoNotificationNewId]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoIdentityIdChangedNotification + object:self + userInfo:userInfo]; + }); +} + +@end + +@interface AWSCognitoCredentialsProviderHelper() + +@property (nonatomic, strong) AWSCognitoIdentity *cognitoIdentity; +@property (nonatomic, strong) AWSExecutor *executor; +@property (atomic, assign) int32_t count; +@property (nonatomic, strong) dispatch_semaphore_t semaphore; +@property (atomic, assign) BOOL hasClearedIdentityId; + +@end + +@implementation AWSCognitoCredentialsProviderHelper + +- (instancetype)initWithRegionType:(AWSRegionType)regionType + identityPoolId:(NSString *)identityPoolId + useEnhancedFlow:(BOOL)useEnhancedFlow + identityProviderManager:(id)identityProviderManager { + if (self = [super init]) { + _executor = [AWSExecutor executorWithOperationQueue:[NSOperationQueue new]]; + _count = 0; + _semaphore = dispatch_semaphore_create(0); + _useEnhancedFlow = useEnhancedFlow; + self.identityPoolId = identityPoolId; + self.identityProviderManager = identityProviderManager; + + AWSAnonymousCredentialsProvider *credentialsProvider = [AWSAnonymousCredentialsProvider new]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:regionType + credentialsProvider:credentialsProvider]; + _cognitoIdentity = [[AWSCognitoIdentity alloc] initWithConfiguration:configuration]; + } + + return self; +} + +#pragma mark - AWSIdentityProvider + +- (NSString *)identityProviderName { + return AWSIdentityProviderAmazonCognitoIdentity; +} + +- (AWSTask *)token { + return [[[self getIdentityId] continueWithSuccessBlock:^id(AWSTask *task) { + // This should never happen, but just in case + if (!self.identityId) { + AWSDDLogError(@"In refresh, but identityId is nil."); + AWSDDLogError(@"Result from getIdentityId is %@", task.result); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}]]; + } + + if (self.identityProviderManager) { + return [self.identityProviderManager logins]; + } else { + return [AWSTask taskWithResult:nil]; + } + }] continueWithSuccessBlock:^id _Nullable(AWSTask* _Nonnull task) { + NSDictionary *logins = task.result; + self.cachedLogins = logins; + + if (self.useEnhancedFlow) { + if(!task.result){ + return task; + } + else { + return [AWSTask taskWithResult:[task.result objectForKey:[self identityProviderName]]]; + } + } + + AWSCognitoIdentityGetOpenIdTokenInput *getTokenInput = [AWSCognitoIdentityGetOpenIdTokenInput new]; + getTokenInput.identityId = self.identityId; + getTokenInput.logins = logins; + + return [[[self.cognitoIdentity getOpenIdToken:getTokenInput] continueWithBlock:^id(AWSTask *task) { + // When an invalid identityId is cached in the keychain for auth, + // we will refresh the identityId and try to get OpenID token again. + if (task.error) { + AWSDDLogError(@"GetOpenIdToken failed. Error is [%@]", task.error); + + // If it's auth or we caught a not found or validation error + // we want to reset the identity id, otherwise, just return + // the error to our caller + if (![AWSCognitoCredentialsProvider shouldResetIdentityId:task.error + authenticated:[self isAuthenticated]]) { + return task; + } + + if (self.hasClearedIdentityId) { + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderErrorDomain + code:AWSCognitoCredentialsProviderInvalidConfiguration + userInfo:@{NSLocalizedDescriptionKey : @"GetCredentialsForIdentity keeps failing. Clearing identityId did not help. Please check your Amazon Cognito Identity configuration."}]]; + } + + AWSDDLogDebug(@"Resetting identity Id and calling getIdentityId"); + // if it's auth, reset id and refetch + self.identityId = nil; + self.hasClearedIdentityId = YES; + + return [[self getIdentityId] continueWithSuccessBlock:^id(AWSTask *task) { + // This should never happen, but just in case + if (!self.identityId) { + AWSDDLogError(@"In refresh, but identitId is nil."); + AWSDDLogError(@"Result from getIdentityId is %@", task.result); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}] + ]; + } + + AWSDDLogDebug(@"Retrying GetOpenIdToken"); + + // retry get token + AWSCognitoIdentityGetOpenIdTokenInput *tokenRetry = [AWSCognitoIdentityGetOpenIdTokenInput new]; + tokenRetry.identityId = self.identityId; + tokenRetry.logins = self.cachedLogins; + + return [self.cognitoIdentity getOpenIdToken:tokenRetry]; + }]; + } + + return task; + }] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetOpenIdTokenResponse *getTokenResponse = task.result; + NSString *token = getTokenResponse.token; + NSString *identityIdFromToken = getTokenResponse.identityId; + + // This should never happen, but just in case + if (!identityIdFromToken) { + AWSDDLogError(@"identityId from getOpenIdToken is nil"); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: @"identityId shouldn't be nil"}] + ]; + } + + if (![self.identityId isEqualToString:identityIdFromToken]) { + self.identityId = identityIdFromToken; + } + + return [AWSTask taskWithResult:token]; + }]; + }]; +} + +#pragma mark - AWSIdentityProviderManager + +- (AWSTask *> *)logins { + if (self.identityProviderManager && self.useEnhancedFlow) { + self.cachedLogins = nil; + return [[self getIdentityId] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + if(self.cachedLogins){ + return [AWSTask taskWithResult:self.cachedLogins]; + } + else { + return [self.identityProviderManager logins]; + } + }]; + } + + return [[self token] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + if (!task.result) { + return [AWSTask taskWithResult:nil]; + } + NSString *token = task.result; + return [AWSTask taskWithResult:@{self.identityProviderName : token}]; + }]; +} + +#pragma mark - + +- (AWSTask *)getIdentityId { + if (self.identityId) { + return [AWSTask taskWithResult:self.identityId]; + } else { + AWSTask *task = [AWSTask taskWithResult:nil]; + if (self.identityProviderManager) { + task = [self.identityProviderManager logins]; + } + return [[task continueWithExecutor:self.executor withSuccessBlock:^id _Nullable(AWSTask *> * _Nonnull task) { + NSDictionary *logins = task.result; + self.cachedLogins = logins; + self.count++; + + // Create an identity id via GetID if the call to logins didn't set it which DevAuth does + // And there are no other calls in flight to create one + if (!self.identityId && self.count <= 1) { + AWSCognitoIdentityGetIdInput *getIdInput = [AWSCognitoIdentityGetIdInput new]; + getIdInput.identityPoolId = self.identityPoolId; + getIdInput.logins = logins; + return [self.cognitoIdentity getId:getIdInput]; + } else { + dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)); + return [AWSTask taskWithResult:nil]; + } + }] continueWithBlock:^id(AWSTask *task) { + if (task.error) { + AWSDDLogError(@"GetId failed. Error is [%@]", task.error); + } else if (task.result) { + AWSCognitoIdentityGetIdResponse *getIdResponse = task.result; + self.identityId = getIdResponse.identityId; + } + + //ensure that the identityID is set before the semaphore is signaled, otherwise it's possible + //that continuation blocks execute before the identityID is set + self.count--; + dispatch_semaphore_signal(self.semaphore); + if (task.faulted) { + return task; + } + if(!self.identityId){ + NSString * error = @"Obtaining an identity id in another thread failed or didn't complete within 5 seconds."; + AWSDDLogError(@"%@",error); + return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain + code:AWSCognitoCredentialsProviderHelperErrorTypeIdentityIsNil + userInfo:@{NSLocalizedDescriptionKey: error}]]; + } else { + return [AWSTask taskWithResult:self.identityId]; + } + }]; + } +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.h b/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.h new file mode 100644 index 00000000..96b1703b --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.h @@ -0,0 +1,101 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import "AWSNetworking.h" + +FOUNDATION_EXPORT NSString *const AWSSignatureV4Algorithm; +FOUNDATION_EXPORT NSString *const AWSSignatureV4Terminator; + +@class AWSEndpoint; + +@protocol AWSCredentialsProvider; + +@interface AWSSignatureSignerUtility : NSObject + ++ (NSData *)sha256HMacWithData:(NSData *)data withKey:(NSData *)key; ++ (NSString *)hashString:(NSString *)stringToHash; ++ (NSData *)hash:(NSData *)dataToHash; ++ (NSString *)hexEncode:(NSString *)string; ++ (NSString *)HMACSign:(NSData *)data withKey:(NSString *)key usingAlgorithm:(uint32_t)algorithm; + +@end + +@interface AWSSignatureV4Signer : NSObject + +@property (nonatomic, strong, readonly) id credentialsProvider; + +- (instancetype)initWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint; + ++ (AWSTask *)generateQueryStringForSignatureV4WithCredentialProvider:(id)credentialsProvider + httpMethod:(AWSHTTPMethod)httpMethod + expireDuration:(int32_t)expireDuration + endpoint:(AWSEndpoint *)endpoint + keyPath:(NSString *)keyPath + requestHeaders:(NSDictionary *)requestHeaders + requestParameters:(NSDictionary *)requestParameters + signBody:(BOOL)signBody; + ++ (NSString *)getCanonicalizedRequest:(NSString *)method + path:(NSString *)path + query:(NSString *)query + headers:(NSDictionary *)headers + contentSha256:(NSString *)contentSha256; + ++ (NSData *)getV4DerivedKey:(NSString *)secret + date:(NSString *)dateStamp + region:(NSString *)regionName + service:(NSString *)serviceName; + ++ (NSString *)getSignedHeadersString:(NSDictionary *)headers; + +@end + +@interface AWSSignatureV2Signer : NSObject + +@property (nonatomic, strong, readonly) id credentialsProvider; + ++ (instancetype)signerWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint; + +- (instancetype)initWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint; + +@end + +/** + * A subclass of NSInputStream that wraps an input stream and adds + * signature of chunk data. + **/ +@interface AWSS3ChunkedEncodingInputStream : NSInputStream + +@property (atomic, assign) int64_t totalLengthOfChunkSignatureSent; +/** + * Initialize the input stream with date, scope, signing key and signature + * of request headers. + **/ +- (instancetype)initWithInputStream:(NSInputStream *)stream + date:(NSDate *)date + scope:(NSString *)scope + kSigning:(NSData *)kSigning + headerSignature:(NSString *)headerSignature; + +/** + * Computes new content length after data being chunked encoded. + **/ ++ (NSUInteger)computeContentLengthForChunkedData:(NSUInteger)dataLength; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.m b/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.m new file mode 100644 index 00000000..753ec32c --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Authentication/AWSSignature.m @@ -0,0 +1,973 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// +#import "AWSSignature.h" + +#import +#import "AWSCategory.h" +#import "AWSService.h" +#import "AWSCredentialsProvider.h" +#import "AWSCocoaLumberjack.h" +#import "AWSBolts.h" + +static NSString *const AWSSigV4Marker = @"AWS4"; +NSString *const AWSSignatureV4Algorithm = @"AWS4-HMAC-SHA256"; +NSString *const AWSSignatureV4Terminator = @"aws4_request"; + +@implementation AWSSignatureSignerUtility + ++ (NSData *)sha256HMacWithData:(NSData *)data withKey:(NSData *)key { + CCHmacContext context; + + CCHmacInit(&context, kCCHmacAlgSHA256, [key bytes], [key length]); + CCHmacUpdate(&context, [data bytes], [data length]); + + unsigned char digestRaw[CC_SHA256_DIGEST_LENGTH]; + NSInteger digestLength = CC_SHA256_DIGEST_LENGTH; + + CCHmacFinal(&context, digestRaw); + + return [NSData dataWithBytes:digestRaw length:digestLength]; +} + ++ (NSString *)hashString:(NSString *)stringToHash { + return [[NSString alloc] initWithData:[self hash:[stringToHash dataUsingEncoding:NSUTF8StringEncoding]] + encoding:NSASCIIStringEncoding]; +} + ++ (NSData *)hash:(NSData *)dataToHash { + if ([dataToHash length] > UINT32_MAX) { + return nil; + } + + const void *cStr = [dataToHash bytes]; + unsigned char result[CC_SHA256_DIGEST_LENGTH]; + + CC_SHA256(cStr, (uint32_t)[dataToHash length], result); + + return [[NSData alloc] initWithBytes:result length:CC_SHA256_DIGEST_LENGTH]; +} + ++ (NSString *)hexEncode:(NSString *)string { + NSUInteger len = [string length]; + unichar *chars = malloc(len * sizeof(unichar)); + + [string getCharacters:chars]; + + NSMutableString *hexString = [NSMutableString new]; + for (NSUInteger i = 0; i < len; i++) { + if ((int)chars[i] < 16) { + [hexString appendString:@"0"]; + } + [hexString appendString:[NSString stringWithFormat:@"%x", chars[i]]]; + } + free(chars); + + return hexString; +} + ++ (NSString *)HMACSign:(NSData *)data withKey:(NSString *)key usingAlgorithm:(CCHmacAlgorithm)algorithm { + CCHmacContext context; + const char *keyCString = [key cStringUsingEncoding:NSASCIIStringEncoding]; + + CCHmacInit(&context, algorithm, keyCString, strlen(keyCString)); + CCHmacUpdate(&context, [data bytes], [data length]); + + // Both SHA1 and SHA256 will fit in here + unsigned char digestRaw[CC_SHA256_DIGEST_LENGTH]; + + NSInteger digestLength = -1; + + switch (algorithm) { + case kCCHmacAlgSHA1: + digestLength = CC_SHA1_DIGEST_LENGTH; + break; + + case kCCHmacAlgSHA256: + digestLength = CC_SHA256_DIGEST_LENGTH; + break; + + default: + AWSDDLogError(@"Unable to sign: unsupported Algorithm."); + return nil; + break; + } + + CCHmacFinal(&context, digestRaw); + + NSData *digestData = [NSData dataWithBytes:digestRaw length:digestLength]; + + return [digestData base64EncodedStringWithOptions:kNilOptions]; +} + +@end + +#pragma mark - AWSSignatureV4Signer + +@interface AWSSignatureV4Signer() + +@property (nonatomic, strong) AWSEndpoint *endpoint; + +@end + +@implementation AWSSignatureV4Signer + ++ (instancetype)signerWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint { + AWSSignatureV4Signer *signer = [[AWSSignatureV4Signer alloc] initWithCredentialsProvider:credentialsProvider + endpoint:endpoint]; + return signer; +} + +- (instancetype)initWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint { + if (self = [super init]) { + _credentialsProvider = credentialsProvider; + _endpoint = endpoint; + } + + return self; +} + +- (AWSTask *)interceptRequest:(NSMutableURLRequest *)request { + [request addValue:request.URL.host forHTTPHeaderField:@"Host"]; + return [[self.credentialsProvider credentials] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCredentials *credentials = task.result; + // clear authorization header if set + [request setValue:nil forHTTPHeaderField:@"Authorization"]; + + if (credentials) { + NSString *authorization; + NSArray *hostArray = [[[request URL] host] componentsSeparatedByString:@"."]; + + [request setValue:credentials.sessionKey forHTTPHeaderField:@"X-Amz-Security-Token"]; + if ([hostArray firstObject] && [[hostArray firstObject] rangeOfString:@"s3"].location != NSNotFound) { + //If it is a S3 Request + authorization = [self signS3RequestV4:request + credentials:credentials]; + } else { + authorization = [self signRequestV4:request + credentials:credentials]; + } + + if (authorization) { + [request setValue:authorization forHTTPHeaderField:@"Authorization"]; + } + } + return nil; + }]; +} + +- (NSString *)signS3RequestV4:(NSMutableURLRequest *)urlRequest + credentials:(AWSCredentials *)credentials { + if ( [urlRequest valueForHTTPHeaderField:@"Content-Type"] == nil) { + [urlRequest addValue:@"binary/octet-stream" forHTTPHeaderField:@"Content-Type"]; + } + + // fix query string + // @"?location" -> @"?location=" + + // NSString *subResource = request.subResource; + // if (nil != subResource + // && [subResource length] > 0 + // && [subResource rangeOfString:@"="].location == NSNotFound) { + // [request setSubResource:[subResource stringByAppendingString:@"="]]; + // [request.urlRequest setURL:request.url]; + // } + + NSDate *date = [NSDate aws_clockSkewFixedDate]; + NSString *dateStamp = [date aws_stringValue:AWSDateShortDateFormat1]; + //NSString *dateTime = [date aws_stringValue:AWSDateAmzDateFormat]; + + NSString *scope = [NSString stringWithFormat:@"%@/%@/%@/%@", dateStamp, self.endpoint.regionName, self.endpoint.serviceName, AWSSignatureV4Terminator]; + NSString *signingCredentials = [NSString stringWithFormat:@"%@/%@", credentials.accessKey, scope]; + + // compute canonical request + NSString *httpMethod = urlRequest.HTTPMethod; + // URL.path returns unescaped path + // For S3, url-encoded URI need to be decoded before generate CanonicalURI, otherwise, signature doesn't match occurs. (I.e. CanonicalURI for "/ios-v2-test-445901470/name%3A" will still be "/ios-v2-test-445901470/name%3A". "%3A" -> ":" -> "%3A") + NSString *cfPath = (NSString*)CFBridgingRelease(CFURLCopyPath((CFURLRef)urlRequest.URL)) ; + NSString *path = [cfPath aws_stringWithURLEncodingPath]; + + if (path.length == 0) { + path = [NSString stringWithFormat:@"/"]; + } + + NSString *query = urlRequest.URL.query; + if (query == nil) { + query = [NSString stringWithFormat:@""]; + } + + // Compute contentSha256 + NSString *contentSha256; + NSInputStream *stream = [urlRequest HTTPBodyStream]; + NSUInteger contentLength = [[urlRequest allHTTPHeaderFields][@"Content-Length"] integerValue]; + if (nil != stream) { + contentSha256 = @"STREAMING-AWS4-HMAC-SHA256-PAYLOAD"; + [urlRequest setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[AWSS3ChunkedEncodingInputStream computeContentLengthForChunkedData:contentLength]] + forHTTPHeaderField:@"Content-Length"]; + [urlRequest setValue:nil forHTTPHeaderField:@"Content-Length"]; //remove Content-Length header if it is a HTTPBodyStream + [urlRequest setValue:@"Chunked" forHTTPHeaderField:@"Transfer-Encoding"]; + [urlRequest addValue:@"aws-chunked" forHTTPHeaderField:@"Content-Encoding"]; //add aws-chunked keyword for s3 chunk upload + [urlRequest setValue:[NSString stringWithFormat:@"%lu", (unsigned long)contentLength] forHTTPHeaderField:@"x-amz-decoded-content-length"]; + } else { + contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hash:[urlRequest HTTPBody]] encoding:NSASCIIStringEncoding]]; + //using Content-Length with value of '0' cause auth issue, remove it. + if (contentLength == 0) { + [urlRequest setValue:nil forHTTPHeaderField:@"Content-Length"]; + } else { + [urlRequest setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[[urlRequest HTTPBody] length]] forHTTPHeaderField:@"Content-Length"]; + } + } + + //[request.urlRequest setValue:dateTime forHTTPHeaderField:@"X-Amz-Date"]; + [urlRequest setValue:contentSha256 forHTTPHeaderField:@"x-amz-content-sha256"]; + + //Set Content-MD5 header field if required by server. + if (([ urlRequest.HTTPMethod isEqualToString:@"PUT"] && ([[[urlRequest URL] query] hasPrefix:@"tagging"] || + [[[urlRequest URL] query] hasPrefix:@"lifecycle"] || + [[[urlRequest URL] query] hasPrefix:@"cors"])) + || ([urlRequest.HTTPMethod isEqualToString:@"POST"] && [[[urlRequest URL] query] hasPrefix:@"delete"]) + ) { + if (![urlRequest valueForHTTPHeaderField:@"Content-MD5"]) { + [urlRequest setValue:[NSString aws_base64md5FromData:urlRequest.HTTPBody] forHTTPHeaderField:@"Content-MD5"]; + } + + } + + NSMutableDictionary *headers = [[urlRequest allHTTPHeaderFields] mutableCopy]; + + NSString *canonicalRequest = [AWSSignatureV4Signer getCanonicalizedRequest:httpMethod + path:path + query:query + headers:headers + contentSha256:contentSha256]; + AWSDDLogVerbose(@"Canonical request: [%@]", canonicalRequest); + + NSString *stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", + AWSSignatureV4Algorithm, + [urlRequest valueForHTTPHeaderField:@"X-Amz-Date"], + scope, + [AWSSignatureSignerUtility hexEncode:[AWSSignatureSignerUtility hashString:canonicalRequest]]]; + AWSDDLogVerbose(@"AWS4 String to Sign: [%@]", stringToSign); + + NSData *kSigning = [AWSSignatureV4Signer getV4DerivedKey:credentials.secretKey + date:dateStamp + region:self.endpoint.regionName + service:self.endpoint.serviceName]; + + NSData *signature = [AWSSignatureSignerUtility sha256HMacWithData:[stringToSign dataUsingEncoding:NSUTF8StringEncoding] + withKey:kSigning]; + NSString *signatureString = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:signature + encoding:NSASCIIStringEncoding]]; + + NSString *authorization = [NSString stringWithFormat:@"%@ Credential=%@, SignedHeaders=%@, Signature=%@", + AWSSignatureV4Algorithm, + signingCredentials, + [AWSSignatureV4Signer getSignedHeadersString:headers], + signatureString]; + + if (nil != stream) { + AWSS3ChunkedEncodingInputStream *chunkedStream = [[AWSS3ChunkedEncodingInputStream alloc] initWithInputStream:stream + date:date + scope:scope + kSigning:kSigning + headerSignature:signatureString]; + [urlRequest setHTTPBodyStream:chunkedStream]; + } + + return authorization; +} + + +- (NSString *)signRequestV4:(NSMutableURLRequest *)request + credentials:(AWSCredentials *)credentials { + + NSString *absoluteString = [request.URL absoluteString]; + if ([absoluteString hasSuffix:@"/"]) { + request.URL = [NSURL URLWithString:[absoluteString substringToIndex:[absoluteString length] - 1]]; + } + + NSDate *xAmzDate = [NSDate aws_dateFromString:[request valueForHTTPHeaderField:@"X-Amz-Date"] + format:AWSDateISO8601DateFormat2]; + + NSString *dateStamp = [xAmzDate aws_stringValue:AWSDateShortDateFormat1]; + + NSString *cfPath = (NSString *)CFBridgingRelease(CFURLCopyPath((CFURLRef)request.URL)); + //For AWS Services (except S3) , url-encoded URL will be used to generate CanonicalURL directly. (i.e. the encoded URL will be encoded again, e.g. "%3A" -> "%253A" + NSString *path = [cfPath aws_stringWithURLEncodingPathWithoutPriorDecoding]; + if (path.length == 0) { + path = [NSString stringWithFormat:@"/"]; + } + NSString *query = request.URL.query; + if (query == nil) { + query = [NSString stringWithFormat:@""]; + } + + NSString *contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hash:request.HTTPBody] encoding:NSASCIIStringEncoding]]; + + NSString *canonicalRequest = [AWSSignatureV4Signer getCanonicalizedRequest:request.HTTPMethod + path:path + query:query + headers:request.allHTTPHeaderFields + contentSha256:contentSha256]; + + AWSDDLogVerbose(@"AWS4 Canonical Request: [%@]", canonicalRequest); + AWSDDLogVerbose(@"payload %@",[[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding]); + + NSString *scope = [NSString stringWithFormat:@"%@/%@/%@/%@", + dateStamp, + self.endpoint.regionName, + self.endpoint.serviceName, + AWSSignatureV4Terminator]; + NSString *signingCredentials = [NSString stringWithFormat:@"%@/%@", + credentials.accessKey, + scope]; + NSString *stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", + AWSSignatureV4Algorithm, + [request valueForHTTPHeaderField:@"X-Amz-Date"], + scope, + [AWSSignatureSignerUtility hexEncode:[AWSSignatureSignerUtility hashString:canonicalRequest]]]; + + AWSDDLogVerbose(@"AWS4 String to Sign: [%@]", stringToSign); + + NSData *kSigning = [AWSSignatureV4Signer getV4DerivedKey:credentials.secretKey + date:dateStamp + region:self.endpoint.regionName + service:self.endpoint.serviceName]; + NSData *signature = [AWSSignatureSignerUtility sha256HMacWithData:[stringToSign dataUsingEncoding:NSUTF8StringEncoding] + withKey:kSigning]; + + NSString *credentialsAuthorizationHeader = [NSString stringWithFormat:@"Credential=%@", signingCredentials]; + NSString *signedHeadersAuthorizationHeader = [NSString stringWithFormat:@"SignedHeaders=%@", [AWSSignatureV4Signer getSignedHeadersString:request.allHTTPHeaderFields]]; + NSString *signatureAuthorizationHeader = [NSString stringWithFormat:@"Signature=%@", [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:signature encoding:NSASCIIStringEncoding]]]; + + NSString *authorization = [NSString stringWithFormat:@"%@ %@, %@, %@", + AWSSignatureV4Algorithm, + credentialsAuthorizationHeader, + signedHeadersAuthorizationHeader, + signatureAuthorizationHeader]; + + return authorization; +} + + ++ (AWSTask *)generateQueryStringForSignatureV4WithCredentialProvider:(id)credentialsProvider + httpMethod:(AWSHTTPMethod)httpMethod + expireDuration:(int32_t)expireDuration + endpoint:(AWSEndpoint *)endpoint + keyPath:(NSString *)keyPath + requestHeaders:(NSDictionary *)requestHeaders + requestParameters:(NSDictionary *)requestParameters + signBody:(BOOL)signBody{ + + return [[credentialsProvider credentials] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCredentials *credentials = task.result; + + //Implementation of V4 signaure http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html + NSMutableString *queryString = [NSMutableString new]; + + //Append Identifies the version of AWS Signature and the algorithm that you used to calculate the signature. + [queryString appendFormat:@"%@=%@&",@"X-Amz-Algorithm",AWSSignatureV4Algorithm]; + + //Get ClockSkew Fixed Date + NSDate *currentDate = [NSDate aws_clockSkewFixedDate]; + + //Format of X-Amz-Credential : ////aws4_request. + NSString *scope = [NSString stringWithFormat:@"%@/%@/%@/%@", + [currentDate aws_stringValue:AWSDateShortDateFormat1], + endpoint.regionName, + endpoint.serviceName, + AWSSignatureV4Terminator]; + + NSString *signingCredentials = [NSString stringWithFormat:@"%@/%@",credentials.accessKey, scope]; + //need to replace "/" with "%2F" + NSString *xAmzCredentialString = [signingCredentials stringByReplacingOccurrencesOfString:@"/" withString:@"\%2F"]; + + [queryString appendFormat:@"%@=%@&",@"X-Amz-Credential",xAmzCredentialString]; + + //X-Amz-Date in ISO 8601 format, for example, 20130721T201207Z. This value must match the date value used to calculate the signature. + [queryString appendFormat:@"%@=%@&",@"X-Amz-Date",[currentDate aws_stringValue:AWSDateISO8601DateFormat2]]; + + //X-Amz-Expires, Provides the time period, in seconds, for which the generated presigned URL is valid. + //For example, 86400 (24 hours). This value is an integer. The minimum value you can set is 1, and the maximum is 604800 (seven days). + [queryString appendFormat:@"%@=%d&", @"X-Amz-Expires", expireDuration]; + + /* + X-Amz-SignedHeaders Lists the headers that you used to calculate the signature. The HTTP host header is required. + Any x-amz-* headers that you plan to add to the request are also required for signature calculation. + In general, for added security, you should sign all the request headers that you plan to include in your request. + */ + + [queryString appendFormat:@"%@=%@&", @"X-Amz-SignedHeaders", [[AWSSignatureV4Signer getSignedHeadersString:requestHeaders] aws_stringWithURLEncoding]]; + + //add additionalParameters to queryString + for (NSString *key in requestParameters) { + if ([requestParameters[key] isKindOfClass:[NSArray class]]) { + NSArray *parameterValues = requestParameters[key]; + for (NSString *paramValue in parameterValues) { + [queryString appendFormat:@"%@=%@&", [key aws_stringWithURLEncoding], [paramValue aws_stringWithURLEncoding]]; + } + } else if ([requestParameters[key] isKindOfClass:[NSString class]]) { + NSString *value = requestParameters[key]; + [queryString appendFormat:@"%@=%@&",[key aws_stringWithURLEncoding], [value aws_stringWithURLEncoding]]; + } else { + // Only @[NSString: NSString] and @[NSString: NSArray] supported currently + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Invalid requestParameters dictionary. Supported Dictionaries include [NSString: NSString] and [NSString: NSArray]" + userInfo:nil]; + } + } + + //add security-token if necessary + if ([credentials.sessionKey length] > 0) { + [queryString appendFormat:@"%@=%@&", @"X-Amz-Security-Token", [credentials.sessionKey aws_stringWithURLEncoding]]; + } + + // ============= generate v4 signature string =================== + + /* Canonical Request Format: + * + * HTTP-VERB + "\n" + (e.g. GET, PUT, POST) + * Canonical URI + "\n" + (e.g. /test.txt) + * Canonical Query String + "\n" (multiple queryString need to sorted by QueryParameter) + * Canonical Headrs + "\n" + (multiple headers need to be sorted by HeaderName) + * Signed Headers + "\n" + (multiple headers need to be sorted by HeaderName) + * "UNSIGNED-PAYLOAD" + */ + + + NSString *httpMethodString = [NSString aws_stringWithHTTPMethod:httpMethod]; + + //CanonicalURI is the URI-encoded version of the absolute path component of the URI—everything starting with the "/" that follows the domain name and up to the end of the string or to the question mark character ('?') if you have query string parameters. e.g. https://s3.amazonaws.com/examplebucket/myphoto.jpg /examplebucket/myphoto.jpg is the absolute path. In the absolute path, you don't encode the "/". + + NSString *canonicalURI = [NSString stringWithFormat:@"/%@", [keyPath aws_stringWithURLEncodingPath]]; //keyPath is not url-encoded. + + NSString *contentSha256; + if(signBody && httpMethod == AWSHTTPMethodGET){ + //in case of http get we sign the body as an empty string only if the sign body flag is set to true + contentSha256 = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:[AWSSignatureSignerUtility hash:[@"" dataUsingEncoding:NSUTF8StringEncoding]] encoding:NSASCIIStringEncoding]]; + }else{ + contentSha256 = @"UNSIGNED-PAYLOAD"; + } + //Generate Canonical Request + NSString *canonicalRequest = [AWSSignatureV4Signer getCanonicalizedRequest:httpMethodString + path:canonicalURI + query:queryString + headers:requestHeaders + contentSha256:contentSha256]; + AWSDDLogVerbose(@"AWSS4 PresignedURL Canonical request: [%@]", canonicalRequest); + + //Generate String to Sign + NSString *stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", + AWSSignatureV4Algorithm, + [currentDate aws_stringValue:AWSDateISO8601DateFormat2], + scope, + [AWSSignatureSignerUtility hexEncode:[AWSSignatureSignerUtility hashString:canonicalRequest]]]; + + AWSDDLogVerbose(@"AWS4 PresignedURL String to Sign: [%@]", stringToSign); + + //Generate Signature + NSData *kSigning = [AWSSignatureV4Signer getV4DerivedKey:credentials.secretKey + date:[currentDate aws_stringValue:AWSDateShortDateFormat1] + region:endpoint.regionName + service:endpoint.serviceName]; + NSData *signature = [AWSSignatureSignerUtility sha256HMacWithData:[stringToSign dataUsingEncoding:NSUTF8StringEncoding] + withKey:kSigning]; + NSString *signatureString = [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:signature + encoding:NSASCIIStringEncoding]]; + + // ============ generate v4 signature string (END) =================== + + [queryString appendFormat:@"%@=%@", @"X-Amz-Signature", signatureString]; + + NSString *urlString = [NSString stringWithFormat:@"%@://%@/%@?%@", endpoint.URL.scheme, endpoint.hostName, keyPath, queryString]; + + return [NSURL URLWithString:urlString]; + }]; +} + + ++ (NSString *)getCanonicalizedRequest:(NSString *)method path:(NSString *)path query:(NSString *)query headers:(NSDictionary *)headers contentSha256:(NSString *)contentSha256 { + NSMutableString *canonicalRequest = [NSMutableString new]; + [canonicalRequest appendString:method]; + [canonicalRequest appendString:@"\n"]; + [canonicalRequest appendString:path]; // Canonicalized resource path + [canonicalRequest appendString:@"\n"]; + + [canonicalRequest appendString:[AWSSignatureV4Signer getCanonicalizedQueryString:query]]; // Canonicalized Query String + [canonicalRequest appendString:@"\n"]; + + [canonicalRequest appendString:[AWSSignatureV4Signer getCanonicalizedHeaderString:headers]]; + [canonicalRequest appendString:@"\n"]; + + [canonicalRequest appendString:[AWSSignatureV4Signer getSignedHeadersString:headers]]; + [canonicalRequest appendString:@"\n"]; + + [canonicalRequest appendString:[NSString stringWithFormat:@"%@", contentSha256]]; + + return canonicalRequest; +} + ++ (NSString *)getCanonicalizedQueryString:(NSString *)query { + NSMutableDictionary *> *queryDictionary = [NSMutableDictionary new]; + [[query componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSArray *components = [obj componentsSeparatedByString:@"="]; + if ([components count] == 2) { + // ?a=b + NSString *key = components[0]; // a + NSString *value = components[1]; // b + if (queryDictionary[key]) { + // If the query parameter has multiple values, add it in the mutable array + [[queryDictionary objectForKey:key] addObject:value]; + } else { + // Insert the value for query parameter as an element in mutable array + [queryDictionary setObject:[@[value] mutableCopy] forKey:key]; + } + } + }]; + + NSMutableArray *sortedQuery = [[NSMutableArray alloc] initWithArray:[queryDictionary allKeys]]; + + [sortedQuery sortUsingSelector:@selector(compare:)]; + + NSMutableString *sortedQueryString = [NSMutableString new]; + for (NSString *key in sortedQuery) { + [queryDictionary[key] sortUsingSelector:@selector(compare:)]; + for (NSString *parameterValue in queryDictionary[key]) { + [sortedQueryString appendString:key]; + [sortedQueryString appendString:@"="]; + [sortedQueryString appendString:parameterValue]; + [sortedQueryString appendString:@"&"]; + } + } + // Remove the trailing & for a valid canonical query string. + if ([sortedQueryString hasSuffix:@"&"]) { + return [sortedQueryString substringToIndex:[sortedQueryString length] - 1]; + } + + return sortedQueryString; +} + ++ (NSString *)getCanonicalizedHeaderString:(NSDictionary *)headers { + NSMutableArray *sortedHeaders = [[NSMutableArray alloc] initWithArray:[headers allKeys]]; + + [sortedHeaders sortUsingSelector:@selector(caseInsensitiveCompare:)]; + + NSMutableString *headerString = [NSMutableString new]; + for (NSString *header in sortedHeaders) { + [headerString appendString:[header lowercaseString]]; + [headerString appendString:@":"]; + [headerString appendString:[headers valueForKey:header]]; + [headerString appendString:@"\n"]; + } + + // SigV4 expects all whitespace in headers and values to be collapsed to a single space + NSCharacterSet *whitespaceChars = [NSCharacterSet whitespaceCharacterSet]; + NSPredicate *noEmptyStrings = [NSPredicate predicateWithFormat:@"SELF != ''"]; + + NSArray *parts = [headerString componentsSeparatedByCharactersInSet:whitespaceChars]; + NSArray *nonWhitespace = [parts filteredArrayUsingPredicate:noEmptyStrings]; + return [nonWhitespace componentsJoinedByString:@" "]; +} + ++ (NSString *)getSignedHeadersString:(NSDictionary *)headers { + NSMutableArray *sortedHeaders = [[NSMutableArray alloc] initWithArray:[headers allKeys]]; + + [sortedHeaders sortUsingSelector:@selector(caseInsensitiveCompare:)]; + + NSMutableString *headerString = [NSMutableString new]; + for (NSString *header in sortedHeaders) { + if ( [headerString length] > 0) { + [headerString appendString:@";"]; + } + [headerString appendString:[header lowercaseString]]; + } + + return headerString; +} + ++ (NSData *)getV4DerivedKey:(NSString *)secret date:(NSString *)dateStamp region:(NSString *)regionName service:(NSString *)serviceName { + // AWS4 uses a series of derived keys, formed by hashing different pieces of data + NSString *kSecret = [NSString stringWithFormat:@"%@%@", AWSSigV4Marker, secret]; + NSData *kDate = [AWSSignatureSignerUtility sha256HMacWithData:[dateStamp dataUsingEncoding:NSUTF8StringEncoding] + withKey:[kSecret dataUsingEncoding:NSUTF8StringEncoding]]; + NSData *kRegion = [AWSSignatureSignerUtility sha256HMacWithData:[regionName dataUsingEncoding:NSASCIIStringEncoding] + withKey:kDate]; + NSData *kService = [AWSSignatureSignerUtility sha256HMacWithData:[serviceName dataUsingEncoding:NSUTF8StringEncoding] + withKey:kRegion]; + NSData *kSigning = [AWSSignatureSignerUtility sha256HMacWithData:[AWSSignatureV4Terminator dataUsingEncoding:NSUTF8StringEncoding] + withKey:kService]; + + //TODO: cache this derived key? + return kSigning; +} + +// For SigV2 ++ (NSString *)canonicalizedQueryString:(NSDictionary *)parameters { + NSMutableString *mutableHTTPBodyString = [NSMutableString new]; + + NSArray *keys = [parameters allKeys]; + NSArray *sortedKeys = [keys sortedArrayUsingSelector:@selector(compare:)]; + for (NSUInteger index = 0; index < [sortedKeys count]; index++) { + NSString *key = [sortedKeys objectAtIndex:index]; + NSString *value = (NSString *)[parameters valueForKey:key]; + + [mutableHTTPBodyString appendString:[key aws_stringWithURLEncoding]]; + [mutableHTTPBodyString appendString:@"="]; + [mutableHTTPBodyString appendString:[value aws_stringWithURLEncoding]]; + + if (index < [sortedKeys count] - 1) { + [mutableHTTPBodyString appendString:@"&"]; + } + } + + return mutableHTTPBodyString; +} + +// For SigV2 ++ (NSString *)getV2StringToSign:(NSMutableURLRequest *)request canonicalizedQueryString:(NSString *)canonicalizedQueryString { + NSString *host = [request.URL host]; + NSString *path = [request.URL path]; + + if (nil == path || [path length] < 1) { + path = @"/"; + } + + NSString *stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", + request.HTTPMethod, + host, + path, + canonicalizedQueryString]; + return stringToSign; +} + +@end + +#pragma mark - AWSSignatureV2Signer + +@interface AWSSignatureV2Signer() + +@property (nonatomic, strong) AWSEndpoint *endpoint; + +@end + +@implementation AWSSignatureV2Signer + ++ (instancetype)signerWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint { + AWSSignatureV2Signer *signer = [[AWSSignatureV2Signer alloc] initWithCredentialsProvider:credentialsProvider + endpoint:endpoint]; + return signer; +} + +- (instancetype)initWithCredentialsProvider:(id)credentialsProvider + endpoint:(AWSEndpoint *)endpoint { + if (self = [super init]) { + _credentialsProvider = credentialsProvider; + _endpoint = endpoint; + } + + return self; +} + +- (AWSTask *)interceptRequest:(NSMutableURLRequest *)request { + return [[self.credentialsProvider credentials] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCredentials *credentials = task.result; + + NSString *HTTPBodyString = [[NSString alloc] initWithData:request.HTTPBody + encoding:NSUTF8StringEncoding]; + NSMutableDictionary *parameters = [NSMutableDictionary new]; + [[HTTPBodyString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"&"]] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSArray *parameter = [obj componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]; + [parameters setValue:parameter[1] forKey:parameter[0]]; + }]; + + [parameters setObject:@"HmacSHA256" forKey:@"SignatureMethod"]; + [parameters setObject:@"2" forKey:@"SignatureVersion"]; + [parameters setObject:credentials.accessKey forKey:@"AWSAccessKeyId"]; + [parameters setObject:[[NSDate aws_clockSkewFixedDate] aws_stringValue:AWSDateISO8601DateFormat3] + forKey:@"Timestamp"]; + //Added SecurityToken field in QueryString for SigV2 if STS has been used. + if (credentials.sessionKey) { + [parameters setObject:credentials.sessionKey forKey:@"SecurityToken"]; + } + + NSMutableString *canonicalizedQueryString = [[AWSSignatureV4Signer canonicalizedQueryString:parameters] mutableCopy]; + NSData *dataToSign = [[AWSSignatureV4Signer getV2StringToSign:request + canonicalizedQueryString:canonicalizedQueryString] dataUsingEncoding:NSUTF8StringEncoding]; + NSString *signature = [AWSSignatureSignerUtility HMACSign:dataToSign + withKey:credentials.secretKey + usingAlgorithm:kCCHmacAlgSHA256]; + [canonicalizedQueryString appendFormat:@"&Signature=%@", [signature aws_stringWithURLEncoding]]; + request.HTTPBody = [canonicalizedQueryString dataUsingEncoding:NSUTF8StringEncoding]; + + return nil; + }]; +} + +@end + +#pragma mark - S3ChunkedEncodingInputStream + +static NSUInteger defaultChunkSize = 32 * 1024 - 91; +static NSString *const emptyStringSha256 = @"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + +@interface AWSS3ChunkedEncodingInputStream() + +// original input stream +@property (nonatomic, strong) NSInputStream *stream; + +// buffer for chunked data plus header +@property (nonatomic, strong) NSMutableData *chunkData; + +// Mark the location of chunkData to be read +@property (nonatomic, assign) NSUInteger location; + +// A flag indicates end of stream +@property (nonatomic, assign) BOOL endOfStream; + +// SigV4 related properties +// Date, used in signing +@property (nonatomic, strong) NSDate *date; + +// Keypath/Scope +@property (nonatomic, strong) NSString *scope; + +// Signature of previous chunk. It's initialized as that of headers. +@property (nonatomic, strong) NSString *priorSha256; + +// SigV4 signing key +@property (nonatomic, strong) NSData *kSigning; + +@end + +@implementation AWSS3ChunkedEncodingInputStream + +@synthesize delegate = _delegate; + +- (instancetype)initWithInputStream:(NSInputStream *)stream + date:(NSDate *)date + scope:(NSString *)scope + kSigning:(NSData *)kSigning + headerSignature:(NSString *)headerSignature { + if (self = [super init]) { + _stream = stream; + _stream.delegate = self; + _date = [date copy]; + _scope = [scope copy]; + _kSigning = [kSigning copy]; + _priorSha256 = [headerSignature copy]; + + // Chunk size plus signature header + NSUInteger chunkSize = defaultChunkSize + [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:defaultChunkSize]; + _chunkData = [[NSMutableData alloc] initWithCapacity:chunkSize]; + } + + return self; +} + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { + if ((eventCode & (1 << 4))) { + // toggle the NSStreamEventEndEncountered bit. + eventCode ^= 1 << 4; + } + if ([self.delegate respondsToSelector:@selector(stream:handleEvent:)]) { + [self.delegate stream:self handleEvent:eventCode]; + } +} + +// Read next chunk of data from stream, and sign the chunk. +// Returns YES on a successful read, NO otherwise. +- (BOOL)nextChunk { + if (self.endOfStream) { + return NO; + } + + // clear current chunkData for next chunk + [self.chunkData setLength:0]; + + uint8_t *chunkBuffer = calloc(defaultChunkSize, sizeof(uint8_t)); + NSInteger read = [self.stream read:chunkBuffer maxLength:defaultChunkSize]; + + // mark end of stream if no data is read + self.endOfStream = (read <= 0); + + // return NO if stream read failed + if (read < 0) { + AWSDDLogError(@"stream read failed streamStatus: %lu streamError: %@", (unsigned long)[self.stream streamStatus], [self.stream streamError].description); + return NO; + } + + NSData *data = [NSData dataWithBytesNoCopy:chunkBuffer length:read]; + [self.chunkData appendData:[self getSignedChunk:data]]; + + AWSDDLogVerbose(@"stream read: %ld, chunk size: %lu", (long)read, (unsigned long)[self.chunkData length]); + + return YES; +} + +// Signs data +- (NSData *)getSignedChunk:(NSData *)data { + NSString *chunkSha256 = [self dataToHexString:[AWSSignatureSignerUtility hash:data]]; + NSString *stringToSign = [NSString stringWithFormat: + @"%@\n%@\n%@\n%@\n%@\n%@", + @"AWS4-HMAC-SHA256-PAYLOAD", + [self.date aws_stringValue:AWSDateISO8601DateFormat2], + self.scope, + self.priorSha256, + emptyStringSha256, + chunkSha256]; + AWSDDLogVerbose(@"AWS4 String to Sign: [%@]", stringToSign); + + NSData *signature = [AWSSignatureSignerUtility sha256HMacWithData:[stringToSign dataUsingEncoding:NSUTF8StringEncoding] + withKey:self.kSigning]; + self.priorSha256 = [self dataToHexString:signature]; + NSString *chunkedHeader = [NSString stringWithFormat:@"%06lx;chunk-signature=%@\r\n", (unsigned long)[data length], self.priorSha256]; + AWSDDLogVerbose(@"AWS4 Chunked Header: [%@]", chunkedHeader); + + NSMutableData *signedChunk = [NSMutableData data]; + [signedChunk appendData:[chunkedHeader dataUsingEncoding:NSUTF8StringEncoding]]; + [signedChunk appendData:data]; + [signedChunk appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + + self.totalLengthOfChunkSignatureSent += [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:0]; + return signedChunk; +} + +- (NSString *)dataToHexString:(NSData *) data { + return [AWSSignatureSignerUtility hexEncode:[[NSString alloc] initWithData:data + encoding:NSASCIIStringEncoding]]; +} + +#pragma mark NSInputStream methods + +- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len { + //change the defaultChunkSize according to caller reading capacity. + defaultChunkSize = len - [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:0]; + // check whether there is data available + if ([self.chunkData length] <= self.location) { + // set up next chunk + if ([self nextChunk]) { + // rewind location + self.location = 0; + } else { + return 0; + } + } + + // compute how many bytes to read from chunk + NSUInteger length = MIN(len, [self.chunkData length] - self.location); + NSRange range = {self.location, length}; + [self.chunkData getBytes:(void *)buffer range:range]; + + // Update location + self.location += length; + + return length; +} + +- (BOOL)hasBytesAvailable { + return !self.endOfStream; +} + +- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len { + return NO; +} + +- (void)open { + [self.stream open]; +} + +- (void)close { + [self.stream close]; +} + +- (void)setDelegate:(id)delegate { + if (delegate == nil) { + _delegate = self; + } else { + _delegate = delegate; + } +} + +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { + [self.stream scheduleInRunLoop:aRunLoop forMode:mode]; +} + +- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { + [self.stream removeFromRunLoop:aRunLoop forMode:mode]; +} + +- (id)propertyForKey:(NSString *)key { + return [self.stream propertyForKey:key]; +} + +- (BOOL)setProperty:(id)property forKey:(NSString *)key { + return [self.stream setProperty:property forKey:key]; +} + +- (NSStreamStatus)streamStatus { + if ([self.stream streamStatus] == NSStreamStatusAtEnd) { + if (self.endOfStream) { + return [self.stream streamStatus]; + } else { + return NSStreamStatusOpen; + } + } else { + return [self.stream streamStatus]; + } +} + +- (NSError *)streamError { + return [self.stream streamError]; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { + return [self.stream methodSignatureForSelector:aSelector]; +} + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + [anInvocation invokeWithTarget:self.stream]; +} + +/** + * Computes the size of one data chunk + * + * ;chunk-signature=\r\n + * \r\n + **/ ++ (NSUInteger)oneChunkedDataSize:(NSUInteger)dataLength { + return [[NSString stringWithFormat:@"%06lx;chunk-signature=%@\r\n", (unsigned long)dataLength, emptyStringSha256] length] + dataLength + [@"\r\n" length]; +} + ++ (NSUInteger)computeContentLengthForChunkedData:(NSUInteger)dataLength { + NSUInteger result = 0; + + // length of full chunks + result += (dataLength / defaultChunkSize) * [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:defaultChunkSize]; + + // length of remaining data + NSUInteger remainingDataLength = dataLength % defaultChunkSize; + if (remainingDataLength > 0) { + result += [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:remainingDataLength]; + } + + // length of final chunk + result += [AWSS3ChunkedEncodingInputStream oneChunkedDataSize:0]; + + return result; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.h new file mode 100644 index 00000000..ce6e4204 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSCancellationToken.h" +#import "AWSCancellationTokenRegistration.h" +#import "AWSCancellationTokenSource.h" +#import "AWSExecutor.h" +#import "AWSGeneric.h" +#import "AWSTask.h" +#import "AWSTaskCompletionSource.h" + + +NS_ASSUME_NONNULL_BEGIN + +/** + A string containing the version of the Bolts Framework used by the current application. + */ +extern NSString *const AWSBoltsFrameworkVersionString; + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.m new file mode 100644 index 00000000..2db5d7bc --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSBolts.m @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSBolts.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const AWSBoltsFrameworkVersionString = @"1.8.4"; + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.h new file mode 100644 index 00000000..eb6943ae --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import "AWSCancellationTokenRegistration.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + A block that will be called when a token is cancelled. + */ +typedef void(^AWSCancellationBlock)(); + +/*! + The consumer view of a CancellationToken. + Propagates notification that operations should be canceled. + A AWSCancellationToken has methods to inspect whether the token has been cancelled. + */ +@interface AWSCancellationToken : NSObject + +/*! + Whether cancellation has been requested for this token source. + */ +@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested; + +/*! + Register a block to be notified when the token is cancelled. + If the token is already cancelled the delegate will be notified immediately. + */ +- (AWSCancellationTokenRegistration *)registerCancellationObserverWithBlock:(AWSCancellationBlock)block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.m new file mode 100644 index 00000000..e32b6699 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationToken.m @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSCancellationToken.h" +#import "AWSCancellationTokenRegistration.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface AWSCancellationToken () + +@property (nullable, nonatomic, strong) NSMutableArray *registrations; +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic) BOOL disposed; + +@end + +@interface AWSCancellationTokenRegistration (AWSCancellationToken) + ++ (instancetype)registrationWithToken:(AWSCancellationToken *)token delegate:(AWSCancellationBlock)delegate; + +- (void)notifyDelegate; + +@end + +@implementation AWSCancellationToken + +@synthesize cancellationRequested = _cancellationRequested; + +#pragma mark - Initializer + +- (instancetype)init { + self = [super init]; + if (!self) return self; + + _registrations = [NSMutableArray array]; + _lock = [NSObject new]; + + return self; +} + +#pragma mark - Custom Setters/Getters + +- (BOOL)isCancellationRequested { + @synchronized(self.lock) { + [self throwIfDisposed]; + return _cancellationRequested; + } +} + +- (void)cancel { + NSArray *registrations; + @synchronized(self.lock) { + [self throwIfDisposed]; + if (_cancellationRequested) { + return; + } + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; + _cancellationRequested = YES; + registrations = [self.registrations copy]; + } + + [self notifyCancellation:registrations]; +} + +- (void)notifyCancellation:(NSArray *)registrations { + for (AWSCancellationTokenRegistration *registration in registrations) { + [registration notifyDelegate]; + } +} + +- (AWSCancellationTokenRegistration *)registerCancellationObserverWithBlock:(AWSCancellationBlock)block { + @synchronized(self.lock) { + AWSCancellationTokenRegistration *registration = [AWSCancellationTokenRegistration registrationWithToken:self delegate:[block copy]]; + [self.registrations addObject:registration]; + + return registration; + } +} + +- (void)unregisterRegistration:(AWSCancellationTokenRegistration *)registration { + @synchronized(self.lock) { + [self throwIfDisposed]; + [self.registrations removeObject:registration]; + } +} + +// Delay on a non-public method to prevent interference with a user calling performSelector or +// cancelPreviousPerformRequestsWithTarget on the public method +- (void)cancelPrivate { + [self cancel]; +} + +- (void)cancelAfterDelay:(int)millis { + [self throwIfDisposed]; + if (millis < -1) { + [NSException raise:NSInvalidArgumentException format:@"Delay must be >= -1"]; + } + + if (millis == 0) { + [self cancel]; + return; + } + + @synchronized(self.lock) { + [self throwIfDisposed]; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; + if (self.cancellationRequested) { + return; + } + + if (millis != -1) { + double delay = (double)millis / 1000; + [self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay]; + } + } +} + +- (void)dispose { + @synchronized(self.lock) { + if (self.disposed) { + return; + } + [self.registrations makeObjectsPerformSelector:@selector(dispose)]; + self.registrations = nil; + self.disposed = YES; + } +} + +- (void)throwIfDisposed { + if (self.disposed) { + [NSException raise:NSInternalInconsistencyException format:@"Object already disposed"]; + } +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.h new file mode 100644 index 00000000..2b158baf --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/*! + Represents the registration of a cancellation observer with a cancellation token. + Can be used to unregister the observer at a later time. + */ +@interface AWSCancellationTokenRegistration : NSObject + +/*! + Removes the cancellation observer registered with the token + and releases all resources associated with this registration. + */ +- (void)dispose; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.m new file mode 100644 index 00000000..8f544c0a --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenRegistration.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSCancellationTokenRegistration.h" + +#import "AWSCancellationToken.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface AWSCancellationTokenRegistration () + +@property (nonatomic, weak) AWSCancellationToken *token; +@property (nullable, nonatomic, strong) AWSCancellationBlock cancellationObserverBlock; +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic) BOOL disposed; + +@end + +@interface AWSCancellationToken (AWSCancellationTokenRegistration) + +- (void)unregisterRegistration:(AWSCancellationTokenRegistration *)registration; + +@end + +@implementation AWSCancellationTokenRegistration + ++ (instancetype)registrationWithToken:(AWSCancellationToken *)token delegate:(AWSCancellationBlock)delegate { + AWSCancellationTokenRegistration *registration = [AWSCancellationTokenRegistration new]; + registration.token = token; + registration.cancellationObserverBlock = delegate; + return registration; +} + +- (instancetype)init { + self = [super init]; + if (!self) return self; + + _lock = [NSObject new]; + + return self; +} + +- (void)dispose { + @synchronized(self.lock) { + if (self.disposed) { + return; + } + self.disposed = YES; + } + + AWSCancellationToken *token = self.token; + if (token != nil) { + [token unregisterRegistration:self]; + self.token = nil; + } + self.cancellationObserverBlock = nil; +} + +- (void)notifyDelegate { + @synchronized(self.lock) { + [self throwIfDisposed]; + self.cancellationObserverBlock(); + } +} + +- (void)throwIfDisposed { + NSAssert(!self.disposed, @"Object already disposed"); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.h new file mode 100644 index 00000000..8356299a --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class AWSCancellationToken; + +/*! + AWSCancellationTokenSource represents the producer side of a CancellationToken. + Signals to a CancellationToken that it should be canceled. + It is a cancellation token that also has methods + for changing the state of a token by cancelling it. + */ +@interface AWSCancellationTokenSource : NSObject + +/*! + Creates a new cancellation token source. + */ ++ (instancetype)cancellationTokenSource; + +/*! + The cancellation token associated with this CancellationTokenSource. + */ +@property (nonatomic, strong, readonly) AWSCancellationToken *token; + +/*! + Whether cancellation has been requested for this token source. + */ +@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested; + +/*! + Cancels the token if it has not already been cancelled. + */ +- (void)cancel; + +/*! + Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds. + @param millis The number of milliseconds to wait before completing the returned task. + If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped. + */ +- (void)cancelAfterDelay:(int)millis; + +/*! + Releases all resources associated with this token source, + including disposing of all registrations. + */ +- (void)dispose; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.m new file mode 100644 index 00000000..cb2360fa --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSCancellationTokenSource.m @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSCancellationTokenSource.h" + +#import "AWSCancellationToken.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface AWSCancellationToken (AWSCancellationTokenSource) + +- (void)cancel; +- (void)cancelAfterDelay:(int)millis; + +- (void)dispose; +- (void)throwIfDisposed; + +@end + +@implementation AWSCancellationTokenSource + +#pragma mark - Initializer + +- (instancetype)init { + self = [super init]; + if (!self) return self; + + _token = [AWSCancellationToken new]; + + return self; +} + ++ (instancetype)cancellationTokenSource { + return [AWSCancellationTokenSource new]; +} + +#pragma mark - Custom Setters/Getters + +- (BOOL)isCancellationRequested { + return _token.isCancellationRequested; +} + +- (void)cancel { + [_token cancel]; +} + +- (void)cancelAfterDelay:(int)millis { + [_token cancelAfterDelay:millis]; +} + +- (void)dispose { + [_token dispose]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.h new file mode 100644 index 00000000..518e044e --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/*! + An object that can run a given block. + */ +@interface AWSExecutor : NSObject + +/*! + Returns a default executor, which runs continuations immediately until the call stack gets too + deep, then dispatches to a new GCD queue. + */ ++ (instancetype)defaultExecutor; + +/*! + Returns an executor that runs continuations on the thread where the previous task was completed. + */ ++ (instancetype)immediateExecutor; + +/*! + Returns an executor that runs continuations on the main thread. + */ ++ (instancetype)mainThreadExecutor; + +/*! + Returns a new executor that uses the given block to execute continuations. + @param block The block to use. + */ ++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `dispatch_queue_t` to dispatch all continuations onto. + */ ++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `NSOperationQueue` to run all continuations on. + */ ++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue; + +/*! + Runs the given block using this executor's particular strategy. + @param block The block to execute. + */ +- (void)execute:(void(^)())block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.m new file mode 100644 index 00000000..c1944a1c --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSExecutor.m @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSExecutor.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +/*! + Get the remaining stack-size of the current thread. + + @param totalSize The total stack size of the current thread. + + @return The remaining size, in bytes, available to the current thread. + + @note This function cannot be inlined, as otherwise the internal implementation could fail to report the proper + remaining stack space. + */ +__attribute__((noinline)) static size_t remaining_stack_size(size_t *restrict totalSize) { + pthread_t currentThread = pthread_self(); + + // NOTE: We must store stack pointers as uint8_t so that the pointer math is well-defined + uint8_t *endStack = pthread_get_stackaddr_np(currentThread); + *totalSize = pthread_get_stacksize_np(currentThread); + + // NOTE: If the function is inlined, this value could be incorrect + uint8_t *frameAddr = __builtin_frame_address(0); + + return (*totalSize) - (size_t)(endStack - frameAddr); +} + +@interface AWSExecutor () + +@property (nonatomic, copy) void(^block)(void(^block)()); + +@end + +@implementation AWSExecutor + +#pragma mark - Executor methods + ++ (instancetype)defaultExecutor { + static AWSExecutor *defaultExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultExecutor = [self executorWithBlock:^void(void(^block)()) { + // We prefer to run everything possible immediately, so that there is callstack information + // when debugging. However, we don't want the stack to get too deep, so if the remaining stack space + // is less than 10% of the total space, we dispatch to another GCD queue. + size_t totalStackSize = 0; + size_t remainingStackSize = remaining_stack_size(&totalStackSize); + + if (remainingStackSize < (totalStackSize / 10)) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); + } else { + @autoreleasepool { + block(); + } + } + }]; + }); + return defaultExecutor; +} + ++ (instancetype)immediateExecutor { + static AWSExecutor *immediateExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + immediateExecutor = [self executorWithBlock:^void(void(^block)()) { + block(); + }]; + }); + return immediateExecutor; +} + ++ (instancetype)mainThreadExecutor { + static AWSExecutor *mainThreadExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + mainThreadExecutor = [self executorWithBlock:^void(void(^block)()) { + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), block); + } else { + @autoreleasepool { + block(); + } + } + }]; + }); + return mainThreadExecutor; +} + ++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block { + return [[self alloc] initWithBlock:block]; +} + ++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue { + return [self executorWithBlock:^void(void(^block)()) { + dispatch_async(queue, block); + }]; +} + ++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue { + return [self executorWithBlock:^void(void(^block)()) { + [queue addOperation:[NSBlockOperation blockOperationWithBlock:block]]; + }]; +} + +#pragma mark - Initializer + +- (instancetype)initWithBlock:(void(^)(void(^block)()))block { + self = [super init]; + if (!self) return self; + + _block = block; + + return self; +} + +#pragma mark - Execution + +- (void)execute:(void(^)())block { + self.block(block); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSGeneric.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSGeneric.h new file mode 100644 index 00000000..c007032e --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSGeneric.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#pragma once + +/** + This exists to use along with `AWSTask` and `AWSTaskCompletionSource`. + + Instead of returning a `AWSTask` with no generic type, or a generic type of 'NSNull' + when there is no usable result from a task, we use the type 'AWSVoid', which will always have a value of `nil`. + + This allows you to provide a more enforced API contract to the caller, + as sending any message to `AWSVoid` will result in a compile time error. + */ +@class _AWSVoid_Nonexistant; +typedef _AWSVoid_Nonexistant *AWSVoid; diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.h new file mode 100644 index 00000000..4d1de570 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import "AWSCancellationToken.h" +#import "AWSGeneric.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + Error domain used if there was multiple errors on . + */ +extern NSString *const AWSTaskErrorDomain; + +/*! + An error code used for , if there were multiple errors. + */ +extern NSInteger const kAWSMultipleErrorsError; + +/*! + An error userInfo key used if there were multiple errors on . + Value type is `NSArray *`. + */ +extern NSString *const AWSTaskMultipleErrorsUserInfoKey; + +@class AWSExecutor; +@class AWSTask; + +/*! + The consumer view of a Task. A AWSTask has methods to + inspect the state of the task, and to add continuations to + be run once the task is complete. + */ +@interface AWSTask<__covariant ResultType> : NSObject + +/*! + A block that can act as a continuation for a task. + */ +typedef __nullable id(^AWSContinuationBlock)(AWSTask *t); + +/*! + Creates a task that is already completed with the given result. + @param result The result for the task. + */ ++ (instancetype)taskWithResult:(nullable ResultType)result; + +/*! + Creates a task that is already completed with the given error. + @param error The error for the task. + */ ++ (instancetype)taskWithError:(NSError *)error; + +/*! + Creates a task that is already cancelled. + */ ++ (instancetype)cancelledTask; + +/*! + Returns a task that will be completed (with result == nil) once + all of the input tasks have completed. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray *)tasks; + +/*! + Returns a task that will be completed once all of the input tasks have completed. + If all tasks complete successfully without being faulted or cancelled the result will be + an `NSArray` of all task results in the order they were provided. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray *)tasks; + +/*! + Returns a task that will be completed once there is at least one successful task. + The first task to successuly complete will set the result, all other tasks results are + ignored. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray *)tasks; + +/*! + Returns a task that will be completed a certain amount of time in the future. + @param millis The approximate number of milliseconds to wait before the + task will be finished (with result == nil). + */ ++ (AWSTask *)taskWithDelay:(int)millis; + +/*! + Returns a task that will be completed a certain amount of time in the future. + @param millis The approximate number of milliseconds to wait before the + task will be finished (with result == nil). + @param token The cancellation token (optional). + */ ++ (AWSTask *)taskWithDelay:(int)millis cancellationToken:(nullable AWSCancellationToken *)token; + +/*! + Returns a task that will be completed after the given block completes with + the specified executor. + @param executor A AWSExecutor responsible for determining how the + continuation block will be run. + @param block The block to immediately schedule to run with the given executor. + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ ++ (instancetype)taskFromExecutor:(AWSExecutor *)executor withBlock:(nullable id (^)())block; + +// Properties that will be set on the task once it is completed. + +/*! + The result of a successful task. + */ +@property (nullable, nonatomic, strong, readonly) ResultType result; + +/*! + The error of a failed task. + */ +@property (nullable, nonatomic, strong, readonly) NSError *error; + +/*! + Whether this task has been cancelled. + */ +@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled; + +/*! + Whether this task has completed due to an error. + */ +@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted; + +/*! + Whether this task has completed. + */ +@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed; + +/*! + Enqueues the given block to be run once this task is complete. + This method uses a default execution strategy. The block will be + run on the thread where the previous task completes, unless the + the stack depth is too deep, in which case it will be run on a + dispatch queue with default priority. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithBlock:(AWSContinuationBlock)block NS_SWIFT_NAME(continueWith(block:)); + +/*! + Enqueues the given block to be run once this task is complete. + This method uses a default execution strategy. The block will be + run on the thread where the previous task completes, unless the + the stack depth is too deep, in which case it will be run on a + dispatch queue with default priority. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithBlock:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken NS_SWIFT_NAME(continueWith(block:cancellationToken:)); + +/*! + Enqueues the given block to be run once this task is complete. + @param executor A AWSExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + withBlock:(AWSContinuationBlock)block NS_SWIFT_NAME(continueWith(executor:block:)); + +/*! + Enqueues the given block to be run once this task is complete. + @param executor A AWSExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + his method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + block:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken +NS_SWIFT_NAME(continueWith(executor:block:cancellationToken:)); + +/*! + Identical to continueWithBlock:, except that the block is only run + if this task did not produce a cancellation or an error. + If it did, then the failure will be propagated to the returned + task. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithSuccessBlock:(AWSContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(block:)); + +/*! + Identical to continueWithBlock:, except that the block is only run + if this task did not produce a cancellation or an error. + If it did, then the failure will be propagated to the returned + task. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithSuccessBlock:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken +NS_SWIFT_NAME(continueOnSuccessWith(block:cancellationToken:)); + +/*! + Identical to continueWithExecutor:withBlock:, except that the block + is only run if this task did not produce a cancellation, error, or an error. + If it did, then the failure will be propagated to the returned task. + @param executor A AWSExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + withSuccessBlock:(AWSContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(executor:block:)); + +/*! + Identical to continueWithExecutor:withBlock:, except that the block + is only run if this task did not produce a cancellation or an error. + If it did, then the failure will be propagated to the returned task. + @param executor A AWSExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a AWSTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + successBlock:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken +NS_SWIFT_NAME(continueOnSuccessWith(executor:block:cancellationToken:)); + +/*! + Waits until this operation is completed. + This method is inefficient and consumes a thread resource while + it's running. It should be avoided. This method logs a warning + message if it is used on the main thread. + */ +- (void)waitUntilFinished; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.m new file mode 100644 index 00000000..29b73fc5 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTask.m @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSTask.h" + +#import + +#import "AWSBolts.h" + +NS_ASSUME_NONNULL_BEGIN + +__attribute__ ((noinline)) void awsbf_warnBlockingOperationOnMainThread() { + NSLog(@"Warning: A long-running operation is being executed on the main thread. \n" + " Break on awsbf_warnBlockingOperationOnMainThread() to debug."); +} + +NSString *const AWSTaskErrorDomain = @"bolts"; +NSInteger const kAWSMultipleErrorsError = 80175001; + +NSString *const AWSTaskMultipleErrorsUserInfoKey = @"errors"; + +@interface AWSTask () { + id _result; + NSError *_error; +} + +@property (nonatomic, assign, readwrite, getter=isCancelled) BOOL cancelled; +@property (nonatomic, assign, readwrite, getter=isFaulted) BOOL faulted; +@property (nonatomic, assign, readwrite, getter=isCompleted) BOOL completed; + +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic, strong) NSCondition *condition; +@property (nonatomic, strong) NSMutableArray *callbacks; + +@end + +@implementation AWSTask + +#pragma mark - Initializer + +- (instancetype)init { + self = [super init]; + if (!self) return self; + + _lock = [[NSObject alloc] init]; + _condition = [[NSCondition alloc] init]; + _callbacks = [NSMutableArray array]; + + return self; +} + +- (instancetype)initWithResult:(id)result { + self = [super init]; + if (!self) return self; + + [self trySetResult:result]; + + return self; +} + +- (instancetype)initWithError:(NSError *)error { + self = [super init]; + if (!self) return self; + + [self trySetError:error]; + + return self; +} + +- (instancetype)initCancelled { + self = [super init]; + if (!self) return self; + + [self trySetCancelled]; + + return self; +} + +#pragma mark - Task Class methods + ++ (instancetype)taskWithResult:(nullable id)result { + return [[self alloc] initWithResult:result]; +} + ++ (instancetype)taskWithError:(NSError *)error { + return [[self alloc] initWithError:error]; +} + ++ (instancetype)cancelledTask { + return [[self alloc] initCancelled]; +} + ++ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray *)tasks { + __block int32_t total = (int32_t)tasks.count; + if (total == 0) { + return [self taskWithResult:nil]; + } + + __block int32_t cancelled = 0; + NSObject *lock = [[NSObject alloc] init]; + NSMutableArray *errors = [NSMutableArray array]; + + AWSTaskCompletionSource *tcs = [AWSTaskCompletionSource taskCompletionSource]; + for (AWSTask *task in tasks) { + [task continueWithBlock:^id(AWSTask *t) { + if (t.error) { + @synchronized (lock) { + [errors addObject:t.error]; + } + } else if (t.cancelled) { + OSAtomicIncrement32Barrier(&cancelled); + } + + if (OSAtomicDecrement32Barrier(&total) == 0) { + if (errors.count > 0) { + if (errors.count == 1) { + tcs.error = [errors firstObject]; + } else { + NSError *error = [NSError errorWithDomain:AWSTaskErrorDomain + code:kAWSMultipleErrorsError + userInfo:@{ AWSTaskMultipleErrorsUserInfoKey: errors }]; + tcs.error = error; + } + } else if (cancelled > 0) { + [tcs cancel]; + } else { + tcs.result = nil; + } + } + return nil; + }]; + } + return tcs.task; +} + ++ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray *)tasks { + return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(AWSTask * __unused task) { + return [tasks valueForKey:@"result"]; + }]; +} + ++ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray *)tasks +{ + __block int32_t total = (int32_t)tasks.count; + if (total == 0) { + return [self taskWithResult:nil]; + } + + __block int completed = 0; + __block int32_t cancelled = 0; + + NSObject *lock = [NSObject new]; + NSMutableArray *errors = [NSMutableArray new]; + + AWSTaskCompletionSource *source = [AWSTaskCompletionSource taskCompletionSource]; + for (AWSTask *task in tasks) { + [task continueWithBlock:^id(AWSTask *t) { + if (t.error != nil) { + @synchronized(lock) { + [errors addObject:t.error]; + } + } else if (t.cancelled) { + OSAtomicIncrement32Barrier(&cancelled); + } else { + if(OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) { + [source setResult:t.result]; + } + } + + if (OSAtomicDecrement32Barrier(&total) == 0 && + OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) { + if (cancelled > 0) { + [source cancel]; + } else if (errors.count > 0) { + if (errors.count == 1) { + source.error = errors.firstObject; + } else { + NSError *error = [NSError errorWithDomain:AWSTaskErrorDomain + code:kAWSMultipleErrorsError + userInfo:@{ @"errors": errors }]; + source.error = error; + } + } + } + // Abort execution of per tasks continuations + return nil; + }]; + } + return source.task; +} + + ++ (AWSTask *)taskWithDelay:(int)millis { + AWSTaskCompletionSource *tcs = [AWSTaskCompletionSource taskCompletionSource]; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); + dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + tcs.result = nil; + }); + return tcs.task; +} + ++ (AWSTask *)taskWithDelay:(int)millis cancellationToken:(nullable AWSCancellationToken *)token { + if (token.cancellationRequested) { + return [AWSTask cancelledTask]; + } + + AWSTaskCompletionSource *tcs = [AWSTaskCompletionSource taskCompletionSource]; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); + dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + if (token.cancellationRequested) { + [tcs cancel]; + return; + } + tcs.result = nil; + }); + return tcs.task; +} + ++ (instancetype)taskFromExecutor:(AWSExecutor *)executor withBlock:(nullable id (^)())block { + return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:^id(AWSTask *task) { + return block(); + }]; +} + +#pragma mark - Custom Setters/Getters + +- (nullable id)result { + @synchronized(self.lock) { + return _result; + } +} + +- (BOOL)trySetResult:(nullable id)result { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + _result = result; + [self runContinuations]; + return YES; + } +} + +- (nullable NSError *)error { + @synchronized(self.lock) { + return _error; + } +} + +- (BOOL)trySetError:(NSError *)error { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + self.faulted = YES; + _error = error; + [self runContinuations]; + return YES; + } +} + +- (BOOL)isCancelled { + @synchronized(self.lock) { + return _cancelled; + } +} + +- (BOOL)isFaulted { + @synchronized(self.lock) { + return _faulted; + } +} + +- (BOOL)trySetCancelled { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + self.cancelled = YES; + [self runContinuations]; + return YES; + } +} + +- (BOOL)isCompleted { + @synchronized(self.lock) { + return _completed; + } +} + +- (void)runContinuations { + @synchronized(self.lock) { + [self.condition lock]; + [self.condition broadcast]; + [self.condition unlock]; + for (void (^callback)() in self.callbacks) { + callback(); + } + [self.callbacks removeAllObjects]; + } +} + +#pragma mark - Chaining methods + +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor withBlock:(AWSContinuationBlock)block { + return [self continueWithExecutor:executor block:block cancellationToken:nil]; +} + +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + block:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken { + AWSTaskCompletionSource *tcs = [AWSTaskCompletionSource taskCompletionSource]; + + // Capture all of the state that needs to used when the continuation is complete. + dispatch_block_t executionBlock = ^{ + if (cancellationToken.cancellationRequested) { + [tcs cancel]; + return; + } + + id result = block(self); + if ([result isKindOfClass:[AWSTask class]]) { + + id (^setupWithTask) (AWSTask *) = ^id(AWSTask *task) { + if (cancellationToken.cancellationRequested || task.cancelled) { + [tcs cancel]; + } else if (task.error) { + tcs.error = task.error; + } else { + tcs.result = task.result; + } + return nil; + }; + + AWSTask *resultTask = (AWSTask *)result; + + if (resultTask.completed) { + setupWithTask(resultTask); + } else { + [resultTask continueWithBlock:setupWithTask]; + } + + } else { + tcs.result = result; + } + }; + + BOOL completed; + @synchronized(self.lock) { + completed = self.completed; + if (!completed) { + [self.callbacks addObject:[^{ + [executor execute:executionBlock]; + } copy]]; + } + } + if (completed) { + [executor execute:executionBlock]; + } + + return tcs.task; +} + +- (AWSTask *)continueWithBlock:(AWSContinuationBlock)block { + return [self continueWithExecutor:[AWSExecutor defaultExecutor] block:block cancellationToken:nil]; +} + +- (AWSTask *)continueWithBlock:(AWSContinuationBlock)block cancellationToken:(nullable AWSCancellationToken *)cancellationToken { + return [self continueWithExecutor:[AWSExecutor defaultExecutor] block:block cancellationToken:cancellationToken]; +} + +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + withSuccessBlock:(AWSContinuationBlock)block { + return [self continueWithExecutor:executor successBlock:block cancellationToken:nil]; +} + +- (AWSTask *)continueWithExecutor:(AWSExecutor *)executor + successBlock:(AWSContinuationBlock)block + cancellationToken:(nullable AWSCancellationToken *)cancellationToken { + if (cancellationToken.cancellationRequested) { + return [AWSTask cancelledTask]; + } + + return [self continueWithExecutor:executor block:^id(AWSTask *task) { + if (task.faulted || task.cancelled) { + return task; + } else { + return block(task); + } + } cancellationToken:cancellationToken]; +} + +- (AWSTask *)continueWithSuccessBlock:(AWSContinuationBlock)block { + return [self continueWithExecutor:[AWSExecutor defaultExecutor] successBlock:block cancellationToken:nil]; +} + +- (AWSTask *)continueWithSuccessBlock:(AWSContinuationBlock)block cancellationToken:(nullable AWSCancellationToken *)cancellationToken { + return [self continueWithExecutor:[AWSExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken]; +} + +#pragma mark - Syncing Task (Avoid it) + +- (void)warnOperationOnMainThread { + awsbf_warnBlockingOperationOnMainThread(); +} + +- (void)waitUntilFinished { + if ([NSThread isMainThread]) { + [self warnOperationOnMainThread]; + } + + @synchronized(self.lock) { + if (self.completed) { + return; + } + [self.condition lock]; + } + // TODO: (nlutsenko) Restructure this to use Bolts-Swift thread access synchronization architecture + // In the meantime, it's absolutely safe to get `_completed` aka an ivar, as long as it's a `BOOL` aka less than word size. + while (!_completed) { + [self.condition wait]; + } + [self.condition unlock]; +} + +#pragma mark - NSObject + +- (NSString *)description { + // Acquire the data from the locked properties + BOOL completed; + BOOL cancelled; + BOOL faulted; + NSString *resultDescription = nil; + + @synchronized(self.lock) { + completed = self.completed; + cancelled = self.cancelled; + faulted = self.faulted; + resultDescription = completed ? [NSString stringWithFormat:@" result = %@", self.result] : @""; + } + + // Description string includes status information and, if available, the + // result since in some ways this is what a promise actually "is". + return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>", + NSStringFromClass([self class]), + self, + completed ? @"YES" : @"NO", + cancelled ? @"YES" : @"NO", + faulted ? @"YES" : @"NO", + resultDescription]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.h b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.h new file mode 100644 index 00000000..5092e56a --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class AWSTask<__covariant ResultType>; + +/*! + A AWSTaskCompletionSource represents the producer side of tasks. + It is a task that also has methods for changing the state of the + task by settings its completion values. + */ +@interface AWSTaskCompletionSource<__covariant ResultType> : NSObject + +/*! + Creates a new unfinished task. + */ ++ (instancetype)taskCompletionSource; + +/*! + The task associated with this TaskCompletionSource. + */ +@property (nonatomic, strong, readonly) AWSTask *task; + +/*! + Completes the task by setting the result. + Attempting to set this for a completed task will raise an exception. + @param result The result of the task. + */ +- (void)setResult:(nullable ResultType)result NS_SWIFT_NAME(set(result:)); + +/*! + Completes the task by setting the error. + Attempting to set this for a completed task will raise an exception. + @param error The error for the task. + */ +- (void)setError:(NSError *)error NS_SWIFT_NAME(set(error:)); + +/*! + Completes the task by marking it as cancelled. + Attempting to set this for a completed task will raise an exception. + */ +- (void)cancel; + +/*! + Sets the result of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetResult:(nullable ResultType)result NS_SWIFT_NAME(trySet(result:)); + +/*! + Sets the error of the task if it wasn't already completed. + @param error The error for the task. + @returns whether the new value was set. + */ +- (BOOL)trySetError:(NSError *)error NS_SWIFT_NAME(trySet(error:)); + +/*! + Sets the cancellation state of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetCancelled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.m b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.m new file mode 100644 index 00000000..5feb22e7 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Bolts/AWSTaskCompletionSource.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "AWSTaskCompletionSource.h" + +#import "AWSTask.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface AWSTask (AWSTaskCompletionSource) + +- (BOOL)trySetResult:(nullable id)result; +- (BOOL)trySetError:(NSError *)error; +- (BOOL)trySetCancelled; + +@end + +@implementation AWSTaskCompletionSource + +#pragma mark - Initializer + ++ (instancetype)taskCompletionSource { + return [[self alloc] init]; +} + +- (instancetype)init { + self = [super init]; + if (!self) return self; + + _task = [[AWSTask alloc] init]; + + return self; +} + +#pragma mark - Custom Setters/Getters + +- (void)setResult:(nullable id)result { + if (![self.task trySetResult:result]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot set the result on a completed task."]; + } +} + +- (void)setError:(NSError *)error { + if (![self.task trySetError:error]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot set the error on a completed task."]; + } +} + +- (void)cancel { + if (![self.task trySetCancelled]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot cancel a completed task."]; + } +} + +- (BOOL)trySetResult:(nullable id)result { + return [self.task trySetResult:result]; +} + +- (BOOL)trySetError:(NSError *)error { + return [self.task trySetError:error]; +} + +- (BOOL)trySetCancelled { + return [self.task trySetCancelled]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.h b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.h new file mode 100644 index 00000000..0f492c43 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.h @@ -0,0 +1,22 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoIdentity.h" +#import "FABKitProtocol.h" +#import "Fabric+FABKits.h" + +@interface AWSCognitoIdentity (Fabric) + +@end diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.m b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.m new file mode 100644 index 00000000..b8604a20 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity+Fabric.m @@ -0,0 +1,65 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// +#import "AWSCognitoIdentity+Fabric.h" + +@implementation AWSCognitoIdentity (Fabric) + +#pragma mark - Fabric + ++ (NSString *)bundleIdentifier { + return @"com.amazonaws.sdk.ios.AWSCognitoIdentity"; +} + ++ (NSString *)kitDisplayVersion { + return AWSiOSSDKVersion; +} + ++ (void)internalInitializeIfNeeded { + // Retrieves the configuration from info.plist. + Class fabricClass = NSClassFromString(@"Fabric"); + if (fabricClass + && [fabricClass respondsToSelector:@selector(configurationDictionaryForKitClass:)]) { + NSDictionary *configurationDictionary = [fabricClass configurationDictionaryForKitClass:[AWSCognitoIdentity class]]; + NSString *defaultRegionTypeString = configurationDictionary[@"AWSDefaultRegionType"]; + AWSRegionType defaultRegionType = [defaultRegionTypeString aws_regionTypeValue]; + NSString *cognitoIdentityRegionTypeString = configurationDictionary[@"AWSCognitoIdentityRegionType"]; + AWSRegionType cognitoIdentityRegionType = [cognitoIdentityRegionTypeString aws_regionTypeValue]; + NSString *cognitoIdentityPoolId = configurationDictionary[@"AWSCognitoIdentityPoolId"]; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Performs some basic configuration check. + if (cognitoIdentityPoolId + && defaultRegionType != AWSRegionUnknown + && cognitoIdentityRegionType != AWSRegionUnknown) { + // Sets up the AWS Mobile SDK. + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:cognitoIdentityRegionType + identityPoolId:cognitoIdentityPoolId]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:defaultRegionType + credentialsProvider:credentialsProvider]; + [configuration addUserAgentProductToken:@"fabric"]; + AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration; + AWSDDLogInfo(@"The default Cognito credentials provider and service configuration were successfully initialized."); + } else { + // The configuration values from info.plist seem invalid. + AWSDDLogWarn(@"Could not find valid 'AWSDefaultRegionType', 'AWSCognitoRegionType', and 'AWSCognitoIdentityPoolId' values in info.plist. Unable to set the default Cognito credentials provider and service configuration. Please follow the instructions on this website and manually set up the AWS Mobile SDK for iOS. http://docs.aws.amazon.com/mobile/sdkforios/developerguide/setup.html"); + } + }); + } else { + AWSDDLogError(@"Fabric is not available."); + } +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity.h b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity.h new file mode 100644 index 00000000..05b53c00 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentity.h @@ -0,0 +1,22 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + + + + +#import "AWSCore.h" +#import "AWSCognitoIdentityService.h" diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.h b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.h new file mode 100644 index 00000000..8c4645bb --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.h @@ -0,0 +1,806 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import "AWSNetworking.h" +#import "AWSModel.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const AWSCognitoIdentityErrorDomain; + +typedef NS_ENUM(NSInteger, AWSCognitoIdentityErrorType) { + AWSCognitoIdentityErrorUnknown, + AWSCognitoIdentityErrorConcurrentModification, + AWSCognitoIdentityErrorDeveloperUserAlreadyRegistered, + AWSCognitoIdentityErrorExternalService, + AWSCognitoIdentityErrorInternalError, + AWSCognitoIdentityErrorInvalidIdentityPoolConfiguration, + AWSCognitoIdentityErrorInvalidParameter, + AWSCognitoIdentityErrorLimitExceeded, + AWSCognitoIdentityErrorNotAuthorized, + AWSCognitoIdentityErrorResourceConflict, + AWSCognitoIdentityErrorResourceNotFound, + AWSCognitoIdentityErrorTooManyRequests, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoIdentityErrorCode) { + AWSCognitoIdentityErrorCodeUnknown, + AWSCognitoIdentityErrorCodeAccessDenied, + AWSCognitoIdentityErrorCodeInternalServerError, +}; + +@class AWSCognitoIdentityCognitoIdentityProvider; +@class AWSCognitoIdentityCreateIdentityPoolInput; +@class AWSCognitoIdentityCredentials; +@class AWSCognitoIdentityDeleteIdentitiesInput; +@class AWSCognitoIdentityDeleteIdentitiesResponse; +@class AWSCognitoIdentityDeleteIdentityPoolInput; +@class AWSCognitoIdentityDescribeIdentityInput; +@class AWSCognitoIdentityDescribeIdentityPoolInput; +@class AWSCognitoIdentityGetCredentialsForIdentityInput; +@class AWSCognitoIdentityGetCredentialsForIdentityResponse; +@class AWSCognitoIdentityGetIdInput; +@class AWSCognitoIdentityGetIdResponse; +@class AWSCognitoIdentityGetIdentityPoolRolesInput; +@class AWSCognitoIdentityGetIdentityPoolRolesResponse; +@class AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput; +@class AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse; +@class AWSCognitoIdentityGetOpenIdTokenInput; +@class AWSCognitoIdentityGetOpenIdTokenResponse; +@class AWSCognitoIdentityIdentityDescription; +@class AWSCognitoIdentityIdentityPool; +@class AWSCognitoIdentityIdentityPoolShortDescription; +@class AWSCognitoIdentityListIdentitiesInput; +@class AWSCognitoIdentityListIdentitiesResponse; +@class AWSCognitoIdentityListIdentityPoolsInput; +@class AWSCognitoIdentityListIdentityPoolsResponse; +@class AWSCognitoIdentityLookupDeveloperIdentityInput; +@class AWSCognitoIdentityLookupDeveloperIdentityResponse; +@class AWSCognitoIdentityMergeDeveloperIdentitiesInput; +@class AWSCognitoIdentityMergeDeveloperIdentitiesResponse; +@class AWSCognitoIdentitySetIdentityPoolRolesInput; +@class AWSCognitoIdentityUnlinkDeveloperIdentityInput; +@class AWSCognitoIdentityUnlinkIdentityInput; +@class AWSCognitoIdentityUnprocessedIdentityId; + +/** +

A provider representing a Cognito User Identity Pool and its client ID.

+ */ +@interface AWSCognitoIdentityCognitoIdentityProvider : AWSModel + + +/** +

The client ID for the Cognito User Identity Pool.

+ */ +@property (nonatomic, strong) NSString * _Nullable clientId; + +/** +

The provider name for a Cognito User Identity Pool. For example, cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789.

+ */ +@property (nonatomic, strong) NSString * _Nullable providerName; + +@end + +/** +

Input to the CreateIdentityPool action.

+ Required parameters: [IdentityPoolName, AllowUnauthenticatedIdentities] + */ +@interface AWSCognitoIdentityCreateIdentityPoolInput : AWSRequest + + +/** +

TRUE if the identity pool supports unauthenticated logins.

+ */ +@property (nonatomic, strong) NSNumber * _Nullable allowUnauthenticatedIdentities; + +/** +

A list representing a Cognito User Identity Pool and its client ID.

+ */ +@property (nonatomic, strong) NSArray * _Nullable cognitoIdentityProviders; + +/** +

The "domain" by which Cognito will refer to your users. This name acts as a placeholder that allows your backend and the Cognito service to communicate about the developer provider. For the DeveloperProviderName, you can use letters as well as period (.), underscore (_), and dash (-).

Once you have set a developer provider name, you cannot change it. Please take care in setting this parameter.

+ */ +@property (nonatomic, strong) NSString * _Nullable developerProviderName; + +/** +

A string that you provide.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolName; + +/** +

A list of OpendID Connect provider ARNs.

+ */ +@property (nonatomic, strong) NSArray * _Nullable openIdConnectProviderARNs; + +/** + + */ +@property (nonatomic, strong) NSArray * _Nullable samlProviderARNs; + +/** +

Optional key:value pairs mapping provider names to provider app IDs.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable supportedLoginProviders; + +@end + +/** +

Credentials for the provided identity ID.

+ */ +@interface AWSCognitoIdentityCredentials : AWSModel + + +/** +

The Access Key portion of the credentials.

+ */ +@property (nonatomic, strong) NSString * _Nullable accessKeyId; + +/** +

The date at which these credentials will expire.

+ */ +@property (nonatomic, strong) NSDate * _Nullable expiration; + +/** +

The Secret Access Key portion of the credentials

+ */ +@property (nonatomic, strong) NSString * _Nullable secretKey; + +/** +

The Session Token portion of the credentials

+ */ +@property (nonatomic, strong) NSString * _Nullable sessionToken; + +@end + +/** +

Input to the DeleteIdentities action.

+ Required parameters: [IdentityIdsToDelete] + */ +@interface AWSCognitoIdentityDeleteIdentitiesInput : AWSRequest + + +/** +

A list of 1-60 identities that you want to delete.

+ */ +@property (nonatomic, strong) NSArray * _Nullable identityIdsToDelete; + +@end + +/** +

Returned in response to a successful DeleteIdentities operation.

+ */ +@interface AWSCognitoIdentityDeleteIdentitiesResponse : AWSModel + + +/** +

An array of UnprocessedIdentityId objects, each of which contains an ErrorCode and IdentityId.

+ */ +@property (nonatomic, strong) NSArray * _Nullable unprocessedIdentityIds; + +@end + +/** +

Input to the DeleteIdentityPool action.

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoIdentityDeleteIdentityPoolInput : AWSRequest + + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

Input to the DescribeIdentity action.

+ Required parameters: [IdentityId] + */ +@interface AWSCognitoIdentityDescribeIdentityInput : AWSRequest + + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +@end + +/** + Input to the DescribeIdentityPool action. + Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoIdentityDescribeIdentityPoolInput : AWSRequest + + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

Input to the GetCredentialsForIdentity action.

+ Required parameters: [IdentityId] + */ +@interface AWSCognitoIdentityGetCredentialsForIdentityInput : AWSRequest + + +/** + + */ +@property (nonatomic, strong) NSString * _Nullable customRoleArn; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A set of optional name-value pairs that map provider names to provider tokens.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable logins; + +@end + +/** +

Returned in response to a successful GetCredentialsForIdentity operation.

+ */ +@interface AWSCognitoIdentityGetCredentialsForIdentityResponse : AWSModel + + +/** +

Credentials for the provided identity ID.

+ */ +@property (nonatomic, strong) AWSCognitoIdentityCredentials * _Nullable credentials; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +@end + +/** + Input to the GetId action. + Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoIdentityGetIdInput : AWSRequest + + +/** + A standard AWS account ID (9+ digits). + */ +@property (nonatomic, strong) NSString * _Nullable accountId; + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

A set of optional name-value pairs that map provider names to provider tokens.

The available provider names for Logins are as follows:

  • Facebook: graph.facebook.com
  • Amazon Cognito Identity Provider: cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789
  • Google: accounts.google.com
  • Amazon: www.amazon.com
  • Twitter: api.twitter.com
  • Digits: www.digits.com

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable logins; + +@end + +/** + Returned in response to a GetId request. + */ +@interface AWSCognitoIdentityGetIdResponse : AWSModel + + +/** + A unique identifier in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +@end + +/** +

Input to the GetIdentityPoolRoles action.

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoIdentityGetIdentityPoolRolesInput : AWSRequest + + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** +

Returned in response to a successful GetIdentityPoolRoles operation.

+ */ +@interface AWSCognitoIdentityGetIdentityPoolRolesResponse : AWSModel + + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

The map of roles associated with this pool. Currently only authenticated and unauthenticated roles are supported.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable roles; + +@end + +/** +

Input to the GetOpenIdTokenForDeveloperIdentity action.

+ Required parameters: [IdentityPoolId, Logins] + */ +@interface AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput : AWSRequest + + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

A set of optional name-value pairs that map provider names to provider tokens. Each name-value pair represents a user from a public provider or developer provider. If the user is from a developer provider, the name-value pair will follow the syntax "developer_provider_name": "developer_user_identifier". The developer provider is the "domain" by which Cognito will refer to your users; you provided this domain while creating/updating the identity pool. The developer user identifier is an identifier from your backend that uniquely identifies a user. When you create an identity pool, you can specify the supported logins.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable logins; + +/** +

The expiration time of the token, in seconds. You can specify a custom expiration time for the token so that you can cache it. If you don't provide an expiration time, the token is valid for 15 minutes. You can exchange the token with Amazon STS for temporary AWS credentials, which are valid for a maximum of one hour. The maximum token duration you can set is 24 hours. You should take care in setting the expiration time for a token, as there are significant security implications: an attacker could use a leaked token to access your AWS resources for the token's duration.

+ */ +@property (nonatomic, strong) NSNumber * _Nullable tokenDuration; + +@end + +/** +

Returned in response to a successful GetOpenIdTokenForDeveloperIdentity request.

+ */ +@interface AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse : AWSModel + + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

An OpenID token.

+ */ +@property (nonatomic, strong) NSString * _Nullable token; + +@end + +/** + Input to the GetOpenIdToken action. + Required parameters: [IdentityId] + */ +@interface AWSCognitoIdentityGetOpenIdTokenInput : AWSRequest + + +/** + A unique identifier in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A set of optional name-value pairs that map provider names to provider tokens. When using graph.facebook.com and www.amazon.com, supply the access_token returned from the provider's authflow. For accounts.google.com, an Amazon Cognito Identity Provider, or any other OpenId Connect provider, always include the id_token.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable logins; + +@end + +/** + Returned in response to a successful GetOpenIdToken request. + */ +@interface AWSCognitoIdentityGetOpenIdTokenResponse : AWSModel + + +/** + A unique identifier in the format REGION:GUID. Note that the IdentityId returned may not match the one passed on input. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + An OpenID token, valid for 15 minutes. + */ +@property (nonatomic, strong) NSString * _Nullable token; + +@end + +/** + A description of the identity. + */ +@interface AWSCognitoIdentityIdentityDescription : AWSModel + + +/** +

Date on which the identity was created.

+ */ +@property (nonatomic, strong) NSDate * _Nullable creationDate; + +/** + A unique identifier in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

Date on which the identity was last modified.

+ */ +@property (nonatomic, strong) NSDate * _Nullable lastModifiedDate; + +/** + A set of optional name-value pairs that map provider names to provider tokens. + */ +@property (nonatomic, strong) NSArray * _Nullable logins; + +@end + +/** + An object representing a Cognito identity pool. + Required parameters: [IdentityPoolId, IdentityPoolName, AllowUnauthenticatedIdentities] + */ +@interface AWSCognitoIdentityIdentityPool : AWSRequest + + +/** + TRUE if the identity pool supports unauthenticated logins. + */ +@property (nonatomic, strong) NSNumber * _Nullable allowUnauthenticatedIdentities; + +/** +

A list representing a Cognito User Identity Pool and its client ID.

+ */ +@property (nonatomic, strong) NSArray * _Nullable cognitoIdentityProviders; + +/** +

The "domain" by which Cognito will refer to your users.

+ */ +@property (nonatomic, strong) NSString * _Nullable developerProviderName; + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

A string that you provide.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolName; + +/** +

A list of OpendID Connect provider ARNs.

+ */ +@property (nonatomic, strong) NSArray * _Nullable openIdConnectProviderARNs; + +/** + + */ +@property (nonatomic, strong) NSArray * _Nullable samlProviderARNs; + +/** +

Optional key:value pairs mapping provider names to provider app IDs.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable supportedLoginProviders; + +@end + +/** + A description of the identity pool. + */ +@interface AWSCognitoIdentityIdentityPoolShortDescription : AWSModel + + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + A string that you provide. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolName; + +@end + +/** + Input to the ListIdentities action. + Required parameters: [IdentityPoolId, MaxResults] + */ +@interface AWSCognitoIdentityListIdentitiesInput : AWSRequest + + +/** +

An optional boolean parameter that allows you to hide disabled identities. If omitted, the ListIdentities API will include disabled identities in the response.

+ */ +@property (nonatomic, strong) NSNumber * _Nullable hideDisabled; + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + The maximum number of identities to return. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + The response to a ListIdentities request. + */ +@interface AWSCognitoIdentityListIdentitiesResponse : AWSModel + + +/** + An object containing a set of identities and associated mappings. + */ +@property (nonatomic, strong) NSArray * _Nullable identities; + +/** + An identity pool ID in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** + A pagination token. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + Input to the ListIdentityPools action. + Required parameters: [MaxResults] + */ +@interface AWSCognitoIdentityListIdentityPoolsInput : AWSRequest + + +/** + The maximum number of identities to return. + */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** + A pagination token. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** + The result of a successful ListIdentityPools action. + */ +@interface AWSCognitoIdentityListIdentityPoolsResponse : AWSModel + + +/** + The identity pools returned by the ListIdentityPools action. + */ +@property (nonatomic, strong) NSArray * _Nullable identityPools; + +/** + A pagination token. + */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** +

Input to the LookupDeveloperIdentityInput action.

+ Required parameters: [IdentityPoolId] + */ +@interface AWSCognitoIdentityLookupDeveloperIdentityInput : AWSRequest + + +/** +

A unique ID used by your backend authentication process to identify a user. Typically, a developer identity provider would issue many developer user identifiers, in keeping with the number of users.

+ */ +@property (nonatomic, strong) NSString * _Nullable developerUserIdentifier; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

The maximum number of identities to return.

+ */ +@property (nonatomic, strong) NSNumber * _Nullable maxResults; + +/** +

A pagination token. The first call you make will have NextToken set to null. After that the service will return NextToken values as needed. For example, let's say you make a request with MaxResults set to 10, and there are 20 matches in the database. The service will return a pagination token as a part of the response. This token can be used to call the API again and get results starting from the 11th match.

+ */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** +

Returned in response to a successful LookupDeveloperIdentity action.

+ */ +@interface AWSCognitoIdentityLookupDeveloperIdentityResponse : AWSModel + + +/** +

This is the list of developer user identifiers associated with an identity ID. Cognito supports the association of multiple developer user identifiers with an identity ID.

+ */ +@property (nonatomic, strong) NSArray * _Nullable developerUserIdentifierList; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

A pagination token. The first call you make will have NextToken set to null. After that the service will return NextToken values as needed. For example, let's say you make a request with MaxResults set to 10, and there are 20 matches in the database. The service will return a pagination token as a part of the response. This token can be used to call the API again and get results starting from the 11th match.

+ */ +@property (nonatomic, strong) NSString * _Nullable nextToken; + +@end + +/** +

Input to the MergeDeveloperIdentities action.

+ Required parameters: [SourceUserIdentifier, DestinationUserIdentifier, DeveloperProviderName, IdentityPoolId] + */ +@interface AWSCognitoIdentityMergeDeveloperIdentitiesInput : AWSRequest + + +/** +

User identifier for the destination user. The value should be a DeveloperUserIdentifier.

+ */ +@property (nonatomic, strong) NSString * _Nullable destinationUserIdentifier; + +/** +

The "domain" by which Cognito will refer to your users. This is a (pseudo) domain name that you provide while creating an identity pool. This name acts as a placeholder that allows your backend and the Cognito service to communicate about the developer provider. For the DeveloperProviderName, you can use letters as well as period (.), underscore (_), and dash (-).

+ */ +@property (nonatomic, strong) NSString * _Nullable developerProviderName; + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

User identifier for the source user. The value should be a DeveloperUserIdentifier.

+ */ +@property (nonatomic, strong) NSString * _Nullable sourceUserIdentifier; + +@end + +/** +

Returned in response to a successful MergeDeveloperIdentities action.

+ */ +@interface AWSCognitoIdentityMergeDeveloperIdentitiesResponse : AWSModel + + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +@end + +/** +

Input to the SetIdentityPoolRoles action.

+ Required parameters: [IdentityPoolId, Roles] + */ +@interface AWSCognitoIdentitySetIdentityPoolRolesInput : AWSRequest + + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +/** +

The map of roles associated with this pool. For a given role, the key will be either "authenticated" or "unauthenticated" and the value will be the Role ARN.

+ */ +@property (nonatomic, strong) NSDictionary * _Nullable roles; + +@end + +/** +

Input to the UnlinkDeveloperIdentity action.

+ Required parameters: [IdentityId, IdentityPoolId, DeveloperProviderName, DeveloperUserIdentifier] + */ +@interface AWSCognitoIdentityUnlinkDeveloperIdentityInput : AWSRequest + + +/** +

The "domain" by which Cognito will refer to your users.

+ */ +@property (nonatomic, strong) NSString * _Nullable developerProviderName; + +/** + A unique ID used by your backend authentication process to identify a user. + */ +@property (nonatomic, strong) NSString * _Nullable developerUserIdentifier; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** +

An identity pool ID in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityPoolId; + +@end + +/** + Input to the UnlinkIdentity action. + Required parameters: [IdentityId, Logins, LoginsToRemove] + */ +@interface AWSCognitoIdentityUnlinkIdentityInput : AWSRequest + + +/** + A unique identifier in the format REGION:GUID. + */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +/** + A set of optional name-value pairs that map provider names to provider tokens. + */ +@property (nonatomic, strong) NSDictionary * _Nullable logins; + +/** + Provider names to unlink from this identity. + */ +@property (nonatomic, strong) NSArray * _Nullable loginsToRemove; + +@end + +/** +

An array of UnprocessedIdentityId objects, each of which contains an ErrorCode and IdentityId.

+ */ +@interface AWSCognitoIdentityUnprocessedIdentityId : AWSModel + + +/** +

The error code indicating the type of error that occurred.

+ */ +@property (nonatomic, assign) AWSCognitoIdentityErrorCode errorCode; + +/** +

A unique identifier in the format REGION:GUID.

+ */ +@property (nonatomic, strong) NSString * _Nullable identityId; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.m b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.m new file mode 100644 index 00000000..b8bd92e2 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityModel.m @@ -0,0 +1,474 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoIdentityModel.h" +#import "AWSCategory.h" + +NSString *const AWSCognitoIdentityErrorDomain = @"com.amazonaws.AWSCognitoIdentityErrorDomain"; + +@implementation AWSCognitoIdentityCognitoIdentityProvider + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"clientId" : @"ClientId", + @"providerName" : @"ProviderName", + }; +} + +@end + +@implementation AWSCognitoIdentityCreateIdentityPoolInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"allowUnauthenticatedIdentities" : @"AllowUnauthenticatedIdentities", + @"cognitoIdentityProviders" : @"CognitoIdentityProviders", + @"developerProviderName" : @"DeveloperProviderName", + @"identityPoolName" : @"IdentityPoolName", + @"openIdConnectProviderARNs" : @"OpenIdConnectProviderARNs", + @"samlProviderARNs" : @"SamlProviderARNs", + @"supportedLoginProviders" : @"SupportedLoginProviders", + }; +} + ++ (NSValueTransformer *)cognitoIdentityProvidersJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoIdentityCognitoIdentityProvider class]]; +} + +@end + +@implementation AWSCognitoIdentityCredentials + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"accessKeyId" : @"AccessKeyId", + @"expiration" : @"Expiration", + @"secretKey" : @"SecretKey", + @"sessionToken" : @"SessionToken", + }; +} + ++ (NSValueTransformer *)expirationJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoIdentityDeleteIdentitiesInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityIdsToDelete" : @"IdentityIdsToDelete", + }; +} + +@end + +@implementation AWSCognitoIdentityDeleteIdentitiesResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"unprocessedIdentityIds" : @"UnprocessedIdentityIds", + }; +} + ++ (NSValueTransformer *)unprocessedIdentityIdsJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoIdentityUnprocessedIdentityId class]]; +} + +@end + +@implementation AWSCognitoIdentityDeleteIdentityPoolInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoIdentityDescribeIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + }; +} + +@end + +@implementation AWSCognitoIdentityDescribeIdentityPoolInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoIdentityGetCredentialsForIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"customRoleArn" : @"CustomRoleArn", + @"identityId" : @"IdentityId", + @"logins" : @"Logins", + }; +} + +@end + +@implementation AWSCognitoIdentityGetCredentialsForIdentityResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"credentials" : @"Credentials", + @"identityId" : @"IdentityId", + }; +} + ++ (NSValueTransformer *)credentialsJSONTransformer { + return [NSValueTransformer awsmtl_JSONDictionaryTransformerWithModelClass:[AWSCognitoIdentityCredentials class]]; +} + +@end + +@implementation AWSCognitoIdentityGetIdInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"accountId" : @"AccountId", + @"identityPoolId" : @"IdentityPoolId", + @"logins" : @"Logins", + }; +} + +@end + +@implementation AWSCognitoIdentityGetIdResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + }; +} + +@end + +@implementation AWSCognitoIdentityGetIdentityPoolRolesInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoIdentityGetIdentityPoolRolesResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + @"roles" : @"Roles", + }; +} + +@end + +@implementation AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"logins" : @"Logins", + @"tokenDuration" : @"TokenDuration", + }; +} + +@end + +@implementation AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"token" : @"Token", + }; +} + +@end + +@implementation AWSCognitoIdentityGetOpenIdTokenInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"logins" : @"Logins", + }; +} + +@end + +@implementation AWSCognitoIdentityGetOpenIdTokenResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"token" : @"Token", + }; +} + +@end + +@implementation AWSCognitoIdentityIdentityDescription + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"creationDate" : @"CreationDate", + @"identityId" : @"IdentityId", + @"lastModifiedDate" : @"LastModifiedDate", + @"logins" : @"Logins", + }; +} + ++ (NSValueTransformer *)creationDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + ++ (NSValueTransformer *)lastModifiedDateJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSNumber *number) { + return [NSDate dateWithTimeIntervalSince1970:[number doubleValue]]; + } reverseBlock:^id(NSDate *date) { + return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]]; + }]; +} + +@end + +@implementation AWSCognitoIdentityIdentityPool + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"allowUnauthenticatedIdentities" : @"AllowUnauthenticatedIdentities", + @"cognitoIdentityProviders" : @"CognitoIdentityProviders", + @"developerProviderName" : @"DeveloperProviderName", + @"identityPoolId" : @"IdentityPoolId", + @"identityPoolName" : @"IdentityPoolName", + @"openIdConnectProviderARNs" : @"OpenIdConnectProviderARNs", + @"samlProviderARNs" : @"SamlProviderARNs", + @"supportedLoginProviders" : @"SupportedLoginProviders", + }; +} + ++ (NSValueTransformer *)cognitoIdentityProvidersJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoIdentityCognitoIdentityProvider class]]; +} + +@end + +@implementation AWSCognitoIdentityIdentityPoolShortDescription + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + @"identityPoolName" : @"IdentityPoolName", + }; +} + +@end + +@implementation AWSCognitoIdentityListIdentitiesInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"hideDisabled" : @"HideDisabled", + @"identityPoolId" : @"IdentityPoolId", + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoIdentityListIdentitiesResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identities" : @"Identities", + @"identityPoolId" : @"IdentityPoolId", + @"nextToken" : @"NextToken", + }; +} + ++ (NSValueTransformer *)identitiesJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoIdentityIdentityDescription class]]; +} + +@end + +@implementation AWSCognitoIdentityListIdentityPoolsInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoIdentityListIdentityPoolsResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPools" : @"IdentityPools", + @"nextToken" : @"NextToken", + }; +} + ++ (NSValueTransformer *)identityPoolsJSONTransformer { + return [NSValueTransformer awsmtl_JSONArrayTransformerWithModelClass:[AWSCognitoIdentityIdentityPoolShortDescription class]]; +} + +@end + +@implementation AWSCognitoIdentityLookupDeveloperIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"developerUserIdentifier" : @"DeveloperUserIdentifier", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + @"maxResults" : @"MaxResults", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoIdentityLookupDeveloperIdentityResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"developerUserIdentifierList" : @"DeveloperUserIdentifierList", + @"identityId" : @"IdentityId", + @"nextToken" : @"NextToken", + }; +} + +@end + +@implementation AWSCognitoIdentityMergeDeveloperIdentitiesInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"destinationUserIdentifier" : @"DestinationUserIdentifier", + @"developerProviderName" : @"DeveloperProviderName", + @"identityPoolId" : @"IdentityPoolId", + @"sourceUserIdentifier" : @"SourceUserIdentifier", + }; +} + +@end + +@implementation AWSCognitoIdentityMergeDeveloperIdentitiesResponse + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + }; +} + +@end + +@implementation AWSCognitoIdentitySetIdentityPoolRolesInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityPoolId" : @"IdentityPoolId", + @"roles" : @"Roles", + }; +} + +@end + +@implementation AWSCognitoIdentityUnlinkDeveloperIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"developerProviderName" : @"DeveloperProviderName", + @"developerUserIdentifier" : @"DeveloperUserIdentifier", + @"identityId" : @"IdentityId", + @"identityPoolId" : @"IdentityPoolId", + }; +} + +@end + +@implementation AWSCognitoIdentityUnlinkIdentityInput + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"identityId" : @"IdentityId", + @"logins" : @"Logins", + @"loginsToRemove" : @"LoginsToRemove", + }; +} + +@end + +@implementation AWSCognitoIdentityUnprocessedIdentityId + ++ (NSDictionary *)JSONKeyPathsByPropertyKey { + return @{ + @"errorCode" : @"ErrorCode", + @"identityId" : @"IdentityId", + }; +} + ++ (NSValueTransformer *)errorCodeJSONTransformer { + return [AWSMTLValueTransformer reversibleTransformerWithForwardBlock:^NSNumber *(NSString *value) { + if ([value caseInsensitiveCompare:@"AccessDenied"] == NSOrderedSame) { + return @(AWSCognitoIdentityErrorCodeAccessDenied); + } + if ([value caseInsensitiveCompare:@"InternalServerError"] == NSOrderedSame) { + return @(AWSCognitoIdentityErrorCodeInternalServerError); + } + return @(AWSCognitoIdentityErrorCodeUnknown); + } reverseBlock:^NSString *(NSNumber *value) { + switch ([value integerValue]) { + case AWSCognitoIdentityErrorCodeAccessDenied: + return @"AccessDenied"; + case AWSCognitoIdentityErrorCodeInternalServerError: + return @"InternalServerError"; + default: + return nil; + } + }]; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.h b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.h new file mode 100644 index 00000000..621e1ce4 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.h @@ -0,0 +1,24 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + +@interface AWSCognitoIdentityResources : NSObject + ++ (instancetype)sharedInstance; + +- (NSDictionary *)JSONObject; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.m b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.m new file mode 100644 index 00000000..59da118e --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityResources.m @@ -0,0 +1,1275 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoIdentityResources.h" +#import "AWSCocoaLumberjack.h" + +@interface AWSCognitoIdentityResources () + +@property (nonatomic, strong) NSDictionary *definitionDictionary; + +@end + +@implementation AWSCognitoIdentityResources + ++ (instancetype)sharedInstance { + static AWSCognitoIdentityResources *_sharedResources = nil; + static dispatch_once_t once_token; + + dispatch_once(&once_token, ^{ + _sharedResources = [AWSCognitoIdentityResources new]; + }); + + return _sharedResources; +} + +- (NSDictionary *)JSONObject { + return self.definitionDictionary; +} + +- (instancetype)init { + if (self = [super init]) { + //init method + NSError *error = nil; + _definitionDictionary = [NSJSONSerialization JSONObjectWithData:[[self definitionString] dataUsingEncoding:NSUTF8StringEncoding] + options:kNilOptions + error:&error]; + if (_definitionDictionary == nil) { + if (error) { + AWSDDLogError(@"Failed to parse JSON service definition: %@",error); + } + } + } + return self; +} + +- (NSString *)definitionString { + return @"{\ + \"version\":\"2.0\",\ + \"metadata\":{\ + \"apiVersion\":\"2014-06-30\",\ + \"endpointPrefix\":\"cognito-identity\",\ + \"jsonVersion\":\"1.1\",\ + \"protocol\":\"json\",\ + \"serviceFullName\":\"Amazon Cognito Identity\",\ + \"signatureVersion\":\"v4\",\ + \"targetPrefix\":\"AWSCognitoIdentityService\"\ + },\ + \"operations\":{\ + \"CreateIdentityPool\":{\ + \"name\":\"CreateIdentityPool\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"CreateIdentityPoolInput\"},\ + \"output\":{\"shape\":\"IdentityPool\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"LimitExceededException\"}\ + ],\ + \"documentation\":\"

Creates a new identity pool. The identity pool is a store of user identity information that is specific to your AWS account. The limit on identity pools is 60 per account. The keys for SupportedLoginProviders are as follows:

  • Facebook: graph.facebook.com
  • Google: accounts.google.com
  • Amazon: www.amazon.com
  • Twitter: api.twitter.com
  • Digits: www.digits.com
You must use AWS Developer credentials to call this API.

\"\ + },\ + \"DeleteIdentities\":{\ + \"name\":\"DeleteIdentities\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"DeleteIdentitiesInput\"},\ + \"output\":{\"shape\":\"DeleteIdentitiesResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Deletes identities from an identity pool. You can specify a list of 1-60 identities that you want to delete.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"DeleteIdentityPool\":{\ + \"name\":\"DeleteIdentityPool\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"DeleteIdentityPoolInput\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Deletes a user pool. Once a pool is deleted, users will not be able to authenticate with the pool.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"DescribeIdentity\":{\ + \"name\":\"DescribeIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"DescribeIdentityInput\"},\ + \"output\":{\"shape\":\"IdentityDescription\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Returns metadata related to the given identity, including when the identity was created and any associated linked logins.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"DescribeIdentityPool\":{\ + \"name\":\"DescribeIdentityPool\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"DescribeIdentityPoolInput\"},\ + \"output\":{\"shape\":\"IdentityPool\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Gets details about a particular identity pool, including the pool name, ID description, creation date, and current number of users.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"GetCredentialsForIdentity\":{\ + \"name\":\"GetCredentialsForIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"GetCredentialsForIdentityInput\"},\ + \"output\":{\"shape\":\"GetCredentialsForIdentityResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InvalidIdentityPoolConfigurationException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"ExternalServiceException\"}\ + ],\ + \"documentation\":\"

Returns credentials for the provided identity ID. Any provided logins will be validated against supported login providers. If the token is for cognito-identity.amazonaws.com, it will be passed through to AWS Security Token Service with the appropriate role for the token.

This is a public API. You do not need any credentials to call this API.

\"\ + },\ + \"GetId\":{\ + \"name\":\"GetId\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"GetIdInput\"},\ + \"output\":{\"shape\":\"GetIdResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"LimitExceededException\"},\ + {\"shape\":\"ExternalServiceException\"}\ + ],\ + \"documentation\":\"

Generates (or retrieves) a Cognito ID. Supplying multiple logins will create an implicit linked account.

This is a public API. You do not need any credentials to call this API.

\"\ + },\ + \"GetIdentityPoolRoles\":{\ + \"name\":\"GetIdentityPoolRoles\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"GetIdentityPoolRolesInput\"},\ + \"output\":{\"shape\":\"GetIdentityPoolRolesResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Gets the roles for an identity pool.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"GetOpenIdToken\":{\ + \"name\":\"GetOpenIdToken\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"GetOpenIdTokenInput\"},\ + \"output\":{\"shape\":\"GetOpenIdTokenResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"ExternalServiceException\"}\ + ],\ + \"documentation\":\"

Gets an OpenID token, using a known Cognito ID. This known Cognito ID is returned by GetId. You can optionally add additional logins for the identity. Supplying multiple logins creates an implicit link.

The OpenId token is valid for 15 minutes.

This is a public API. You do not need any credentials to call this API.

\"\ + },\ + \"GetOpenIdTokenForDeveloperIdentity\":{\ + \"name\":\"GetOpenIdTokenForDeveloperIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"GetOpenIdTokenForDeveloperIdentityInput\"},\ + \"output\":{\"shape\":\"GetOpenIdTokenForDeveloperIdentityResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"DeveloperUserAlreadyRegisteredException\"}\ + ],\ + \"documentation\":\"

Registers (or retrieves) a Cognito IdentityId and an OpenID Connect token for a user authenticated by your backend authentication process. Supplying multiple logins will create an implicit linked account. You can only specify one developer provider as part of the Logins map, which is linked to the identity pool. The developer provider is the \\\"domain\\\" by which Cognito will refer to your users.

You can use GetOpenIdTokenForDeveloperIdentity to create a new identity and to link new logins (that is, user credentials issued by a public provider or developer provider) to an existing identity. When you want to create a new identity, the IdentityId should be null. When you want to associate a new login with an existing authenticated/unauthenticated identity, you can do so by providing the existing IdentityId. This API will create the identity in the specified IdentityPoolId.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"ListIdentities\":{\ + \"name\":\"ListIdentities\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"ListIdentitiesInput\"},\ + \"output\":{\"shape\":\"ListIdentitiesResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Lists the identities in a pool.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"ListIdentityPools\":{\ + \"name\":\"ListIdentityPools\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"ListIdentityPoolsInput\"},\ + \"output\":{\"shape\":\"ListIdentityPoolsResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Lists all of the Cognito identity pools registered for your account.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"LookupDeveloperIdentity\":{\ + \"name\":\"LookupDeveloperIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"LookupDeveloperIdentityInput\"},\ + \"output\":{\"shape\":\"LookupDeveloperIdentityResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Retrieves the IdentityID associated with a DeveloperUserIdentifier or the list of DeveloperUserIdentifiers associated with an IdentityId for an existing identity. Either IdentityID or DeveloperUserIdentifier must not be null. If you supply only one of these values, the other value will be searched in the database and returned as a part of the response. If you supply both, DeveloperUserIdentifier will be matched against IdentityID. If the values are verified against the database, the response returns both values and is the same as the request. Otherwise a ResourceConflictException is thrown.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"MergeDeveloperIdentities\":{\ + \"name\":\"MergeDeveloperIdentities\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"MergeDeveloperIdentitiesInput\"},\ + \"output\":{\"shape\":\"MergeDeveloperIdentitiesResponse\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Merges two users having different IdentityIds, existing in the same identity pool, and identified by the same developer provider. You can use this action to request that discrete users be merged and identified as a single user in the Cognito environment. Cognito associates the given source user (SourceUserIdentifier) with the IdentityId of the DestinationUserIdentifier. Only developer-authenticated users can be merged. If the users to be merged are associated with the same public provider, but as two different users, an exception will be thrown.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"SetIdentityPoolRoles\":{\ + \"name\":\"SetIdentityPoolRoles\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"SetIdentityPoolRolesInput\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"ConcurrentModificationException\"}\ + ],\ + \"documentation\":\"

Sets the roles for an identity pool. These roles are used when making calls to GetCredentialsForIdentity action.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"UnlinkDeveloperIdentity\":{\ + \"name\":\"UnlinkDeveloperIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"UnlinkDeveloperIdentityInput\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"}\ + ],\ + \"documentation\":\"

Unlinks a DeveloperUserIdentifier from an existing identity. Unlinked developer users will be considered new identities next time they are seen. If, for a given Cognito identity, you remove all federated identities as well as the developer user identifier, the Cognito identity becomes inaccessible.

You must use AWS Developer credentials to call this API.

\"\ + },\ + \"UnlinkIdentity\":{\ + \"name\":\"UnlinkIdentity\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"UnlinkIdentityInput\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"ExternalServiceException\"}\ + ],\ + \"documentation\":\"

Unlinks a federated identity from an existing account. Unlinked logins will be considered new identities next time they are seen. Removing the last linked login will make this identity inaccessible.

This is a public API. You do not need any credentials to call this API.

\"\ + },\ + \"UpdateIdentityPool\":{\ + \"name\":\"UpdateIdentityPool\",\ + \"http\":{\ + \"method\":\"POST\",\ + \"requestUri\":\"/\"\ + },\ + \"input\":{\"shape\":\"IdentityPool\"},\ + \"output\":{\"shape\":\"IdentityPool\"},\ + \"errors\":[\ + {\"shape\":\"InvalidParameterException\"},\ + {\"shape\":\"ResourceNotFoundException\"},\ + {\"shape\":\"NotAuthorizedException\"},\ + {\"shape\":\"ResourceConflictException\"},\ + {\"shape\":\"TooManyRequestsException\"},\ + {\"shape\":\"InternalErrorException\"},\ + {\"shape\":\"ConcurrentModificationException\"},\ + {\"shape\":\"LimitExceededException\"}\ + ],\ + \"documentation\":\"

Updates a user pool.

You must use AWS Developer credentials to call this API.

\"\ + }\ + },\ + \"shapes\":{\ + \"ARNString\":{\ + \"type\":\"string\",\ + \"max\":2048,\ + \"min\":20\ + },\ + \"AccessKeyString\":{\"type\":\"string\"},\ + \"AccountId\":{\ + \"type\":\"string\",\ + \"max\":15,\ + \"min\":1,\ + \"pattern\":\"\\\\d+\"\ + },\ + \"CognitoIdentityProvider\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"ProviderName\":{\ + \"shape\":\"CognitoIdentityProviderName\",\ + \"documentation\":\"

The provider name for a Cognito User Identity Pool. For example, cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789.

\"\ + },\ + \"ClientId\":{\ + \"shape\":\"CognitoIdentityProviderClientId\",\ + \"documentation\":\"

The client ID for the Cognito User Identity Pool.

\"\ + }\ + },\ + \"documentation\":\"

A provider representing a Cognito User Identity Pool and its client ID.

\"\ + },\ + \"CognitoIdentityProviderClientId\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[\\\\w_]+\"\ + },\ + \"CognitoIdentityProviderList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"CognitoIdentityProvider\"}\ + },\ + \"CognitoIdentityProviderName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[\\\\w._:/-]+\"\ + },\ + \"ConcurrentModificationException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"

The message returned by a ConcurrentModificationException.

\"\ + }\ + },\ + \"documentation\":\"

Thrown if there are parallel requests to modify a resource.

\",\ + \"exception\":true\ + },\ + \"CreateIdentityPoolInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolName\",\ + \"AllowUnauthenticatedIdentities\"\ + ],\ + \"members\":{\ + \"IdentityPoolName\":{\ + \"shape\":\"IdentityPoolName\",\ + \"documentation\":\"

A string that you provide.

\"\ + },\ + \"AllowUnauthenticatedIdentities\":{\ + \"shape\":\"IdentityPoolUnauthenticated\",\ + \"documentation\":\"

TRUE if the identity pool supports unauthenticated logins.

\"\ + },\ + \"SupportedLoginProviders\":{\ + \"shape\":\"IdentityProviders\",\ + \"documentation\":\"

Optional key:value pairs mapping provider names to provider app IDs.

\"\ + },\ + \"DeveloperProviderName\":{\ + \"shape\":\"DeveloperProviderName\",\ + \"documentation\":\"

The \\\"domain\\\" by which Cognito will refer to your users. This name acts as a placeholder that allows your backend and the Cognito service to communicate about the developer provider. For the DeveloperProviderName, you can use letters as well as period (.), underscore (_), and dash (-).

Once you have set a developer provider name, you cannot change it. Please take care in setting this parameter.

\"\ + },\ + \"OpenIdConnectProviderARNs\":{\ + \"shape\":\"OIDCProviderList\",\ + \"documentation\":\"

A list of OpendID Connect provider ARNs.

\"\ + },\ + \"CognitoIdentityProviders\":{\ + \"shape\":\"CognitoIdentityProviderList\",\ + \"documentation\":\"

A list representing a Cognito User Identity Pool and its client ID.

\"\ + },\ + \"SamlProviderARNs\":{\"shape\":\"SAMLProviderList\"}\ + },\ + \"documentation\":\"

Input to the CreateIdentityPool action.

\"\ + },\ + \"Credentials\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"AccessKeyId\":{\ + \"shape\":\"AccessKeyString\",\ + \"documentation\":\"

The Access Key portion of the credentials.

\"\ + },\ + \"SecretKey\":{\ + \"shape\":\"SecretKeyString\",\ + \"documentation\":\"

The Secret Access Key portion of the credentials

\"\ + },\ + \"SessionToken\":{\ + \"shape\":\"SessionTokenString\",\ + \"documentation\":\"

The Session Token portion of the credentials

\"\ + },\ + \"Expiration\":{\ + \"shape\":\"DateType\",\ + \"documentation\":\"

The date at which these credentials will expire.

\"\ + }\ + },\ + \"documentation\":\"

Credentials for the provided identity ID.

\"\ + },\ + \"DateType\":{\"type\":\"timestamp\"},\ + \"DeleteIdentitiesInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityIdsToDelete\"],\ + \"members\":{\ + \"IdentityIdsToDelete\":{\ + \"shape\":\"IdentityIdList\",\ + \"documentation\":\"

A list of 1-60 identities that you want to delete.

\"\ + }\ + },\ + \"documentation\":\"

Input to the DeleteIdentities action.

\"\ + },\ + \"DeleteIdentitiesResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"UnprocessedIdentityIds\":{\ + \"shape\":\"UnprocessedIdentityIdList\",\ + \"documentation\":\"

An array of UnprocessedIdentityId objects, each of which contains an ErrorCode and IdentityId.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful DeleteIdentities operation.

\"\ + },\ + \"DeleteIdentityPoolInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + }\ + },\ + \"documentation\":\"

Input to the DeleteIdentityPool action.

\"\ + },\ + \"DescribeIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityId\"],\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + }\ + },\ + \"documentation\":\"

Input to the DescribeIdentity action.

\"\ + },\ + \"DescribeIdentityPoolInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + }\ + },\ + \"documentation\":\"Input to the DescribeIdentityPool action.\"\ + },\ + \"DeveloperProviderName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[\\\\w._-]+\"\ + },\ + \"DeveloperUserAlreadyRegisteredException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"

This developer user identifier is already registered with Cognito.

\"\ + }\ + },\ + \"documentation\":\"

The provided developer user identifier is already registered with Cognito under a different identity ID.

\",\ + \"exception\":true\ + },\ + \"DeveloperUserIdentifier\":{\ + \"type\":\"string\",\ + \"max\":1024,\ + \"min\":1,\ + \"pattern\":\"[\\\\w.@_-]+\"\ + },\ + \"DeveloperUserIdentifierList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"DeveloperUserIdentifier\"}\ + },\ + \"ErrorCode\":{\ + \"type\":\"string\",\ + \"enum\":[\ + \"AccessDenied\",\ + \"InternalServerError\"\ + ]\ + },\ + \"ExternalServiceException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"

The message returned by an ExternalServiceException

\"\ + }\ + },\ + \"documentation\":\"

An exception thrown when a dependent service such as Facebook or Twitter is not responding

\",\ + \"exception\":true\ + },\ + \"GetCredentialsForIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityId\"],\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsMap\",\ + \"documentation\":\"

A set of optional name-value pairs that map provider names to provider tokens.

\"\ + },\ + \"CustomRoleArn\":{\"shape\":\"ARNString\"}\ + },\ + \"documentation\":\"

Input to the GetCredentialsForIdentity action.

\"\ + },\ + \"GetCredentialsForIdentityResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"Credentials\":{\ + \"shape\":\"Credentials\",\ + \"documentation\":\"

Credentials for the provided identity ID.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful GetCredentialsForIdentity operation.

\"\ + },\ + \"GetIdInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"AccountId\":{\ + \"shape\":\"AccountId\",\ + \"documentation\":\"A standard AWS account ID (9+ digits).\"\ + },\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsMap\",\ + \"documentation\":\"

A set of optional name-value pairs that map provider names to provider tokens.

The available provider names for Logins are as follows:

  • Facebook: graph.facebook.com
  • Amazon Cognito Identity Provider: cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789
  • Google: accounts.google.com
  • Amazon: www.amazon.com
  • Twitter: api.twitter.com
  • Digits: www.digits.com

\"\ + }\ + },\ + \"documentation\":\"Input to the GetId action.\"\ + },\ + \"GetIdResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A unique identifier in the format REGION:GUID.\"\ + }\ + },\ + \"documentation\":\"Returned in response to a GetId request.\"\ + },\ + \"GetIdentityPoolRolesInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + }\ + },\ + \"documentation\":\"

Input to the GetIdentityPoolRoles action.

\"\ + },\ + \"GetIdentityPoolRolesResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + },\ + \"Roles\":{\ + \"shape\":\"RolesMap\",\ + \"documentation\":\"

The map of roles associated with this pool. Currently only authenticated and unauthenticated roles are supported.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful GetIdentityPoolRoles operation.

\"\ + },\ + \"GetOpenIdTokenForDeveloperIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"Logins\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsMap\",\ + \"documentation\":\"

A set of optional name-value pairs that map provider names to provider tokens. Each name-value pair represents a user from a public provider or developer provider. If the user is from a developer provider, the name-value pair will follow the syntax \\\"developer_provider_name\\\": \\\"developer_user_identifier\\\". The developer provider is the \\\"domain\\\" by which Cognito will refer to your users; you provided this domain while creating/updating the identity pool. The developer user identifier is an identifier from your backend that uniquely identifies a user. When you create an identity pool, you can specify the supported logins.

\"\ + },\ + \"TokenDuration\":{\ + \"shape\":\"TokenDuration\",\ + \"documentation\":\"

The expiration time of the token, in seconds. You can specify a custom expiration time for the token so that you can cache it. If you don't provide an expiration time, the token is valid for 15 minutes. You can exchange the token with Amazon STS for temporary AWS credentials, which are valid for a maximum of one hour. The maximum token duration you can set is 24 hours. You should take care in setting the expiration time for a token, as there are significant security implications: an attacker could use a leaked token to access your AWS resources for the token's duration.

\"\ + }\ + },\ + \"documentation\":\"

Input to the GetOpenIdTokenForDeveloperIdentity action.

\"\ + },\ + \"GetOpenIdTokenForDeveloperIdentityResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"Token\":{\ + \"shape\":\"OIDCToken\",\ + \"documentation\":\"

An OpenID token.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful GetOpenIdTokenForDeveloperIdentity request.

\"\ + },\ + \"GetOpenIdTokenInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityId\"],\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A unique identifier in the format REGION:GUID.\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsMap\",\ + \"documentation\":\"

A set of optional name-value pairs that map provider names to provider tokens. When using graph.facebook.com and www.amazon.com, supply the access_token returned from the provider's authflow. For accounts.google.com, an Amazon Cognito Identity Provider, or any other OpenId Connect provider, always include the id_token.

\"\ + }\ + },\ + \"documentation\":\"Input to the GetOpenIdToken action.\"\ + },\ + \"GetOpenIdTokenResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A unique identifier in the format REGION:GUID. Note that the IdentityId returned may not match the one passed on input.\"\ + },\ + \"Token\":{\ + \"shape\":\"OIDCToken\",\ + \"documentation\":\"An OpenID token, valid for 15 minutes.\"\ + }\ + },\ + \"documentation\":\"Returned in response to a successful GetOpenIdToken request.\"\ + },\ + \"HideDisabled\":{\"type\":\"boolean\"},\ + \"IdentitiesList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"IdentityDescription\"}\ + },\ + \"IdentityDescription\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A unique identifier in the format REGION:GUID.\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsList\",\ + \"documentation\":\"A set of optional name-value pairs that map provider names to provider tokens.\"\ + },\ + \"CreationDate\":{\ + \"shape\":\"DateType\",\ + \"documentation\":\"

Date on which the identity was created.

\"\ + },\ + \"LastModifiedDate\":{\ + \"shape\":\"DateType\",\ + \"documentation\":\"

Date on which the identity was last modified.

\"\ + }\ + },\ + \"documentation\":\"A description of the identity.\"\ + },\ + \"IdentityId\":{\ + \"type\":\"string\",\ + \"max\":55,\ + \"min\":1,\ + \"pattern\":\"[\\\\w-]+:[0-9a-f-]+\"\ + },\ + \"IdentityIdList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"IdentityId\"},\ + \"max\":60,\ + \"min\":1\ + },\ + \"IdentityPool\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"IdentityPoolName\",\ + \"AllowUnauthenticatedIdentities\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + },\ + \"IdentityPoolName\":{\ + \"shape\":\"IdentityPoolName\",\ + \"documentation\":\"

A string that you provide.

\"\ + },\ + \"AllowUnauthenticatedIdentities\":{\ + \"shape\":\"IdentityPoolUnauthenticated\",\ + \"documentation\":\"TRUE if the identity pool supports unauthenticated logins.\"\ + },\ + \"SupportedLoginProviders\":{\ + \"shape\":\"IdentityProviders\",\ + \"documentation\":\"

Optional key:value pairs mapping provider names to provider app IDs.

\"\ + },\ + \"DeveloperProviderName\":{\ + \"shape\":\"DeveloperProviderName\",\ + \"documentation\":\"

The \\\"domain\\\" by which Cognito will refer to your users.

\"\ + },\ + \"OpenIdConnectProviderARNs\":{\ + \"shape\":\"OIDCProviderList\",\ + \"documentation\":\"

A list of OpendID Connect provider ARNs.

\"\ + },\ + \"CognitoIdentityProviders\":{\ + \"shape\":\"CognitoIdentityProviderList\",\ + \"documentation\":\"

A list representing a Cognito User Identity Pool and its client ID.

\"\ + },\ + \"SamlProviderARNs\":{\"shape\":\"SAMLProviderList\"}\ + },\ + \"documentation\":\"An object representing a Cognito identity pool.\"\ + },\ + \"IdentityPoolId\":{\ + \"type\":\"string\",\ + \"max\":55,\ + \"min\":1,\ + \"pattern\":\"[\\\\w-]+:[0-9a-f-]+\"\ + },\ + \"IdentityPoolName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[\\\\w ]+\"\ + },\ + \"IdentityPoolShortDescription\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + },\ + \"IdentityPoolName\":{\ + \"shape\":\"IdentityPoolName\",\ + \"documentation\":\"A string that you provide.\"\ + }\ + },\ + \"documentation\":\"A description of the identity pool.\"\ + },\ + \"IdentityPoolUnauthenticated\":{\"type\":\"boolean\"},\ + \"IdentityPoolsList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"IdentityPoolShortDescription\"}\ + },\ + \"IdentityProviderId\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1,\ + \"pattern\":\"[\\\\w.;_/-]+\"\ + },\ + \"IdentityProviderName\":{\ + \"type\":\"string\",\ + \"max\":128,\ + \"min\":1\ + },\ + \"IdentityProviderToken\":{\ + \"type\":\"string\",\ + \"max\":50000,\ + \"min\":1\ + },\ + \"IdentityProviders\":{\ + \"type\":\"map\",\ + \"key\":{\"shape\":\"IdentityProviderName\"},\ + \"value\":{\"shape\":\"IdentityProviderId\"},\ + \"max\":10\ + },\ + \"InternalErrorException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by an InternalErrorException.\"\ + }\ + },\ + \"documentation\":\"Thrown when the service encounters an error during processing the request.\",\ + \"exception\":true,\ + \"fault\":true\ + },\ + \"InvalidIdentityPoolConfigurationException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"

The message returned for an InvalidIdentityPoolConfigurationException

\"\ + }\ + },\ + \"documentation\":\"

Thrown if the identity pool has no role associated for the given auth type (auth/unauth) or if the AssumeRole fails.

\",\ + \"exception\":true\ + },\ + \"InvalidParameterException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by an InvalidParameterException.\"\ + }\ + },\ + \"documentation\":\"Thrown for missing or bad input parameter(s).\",\ + \"exception\":true\ + },\ + \"LimitExceededException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by a LimitExceededException.\"\ + }\ + },\ + \"documentation\":\"Thrown when the total number of user pools has exceeded a preset limit.\",\ + \"exception\":true\ + },\ + \"ListIdentitiesInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"MaxResults\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"QueryLimit\",\ + \"documentation\":\"The maximum number of identities to return.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"A pagination token.\"\ + },\ + \"HideDisabled\":{\ + \"shape\":\"HideDisabled\",\ + \"documentation\":\"

An optional boolean parameter that allows you to hide disabled identities. If omitted, the ListIdentities API will include disabled identities in the response.

\"\ + }\ + },\ + \"documentation\":\"Input to the ListIdentities action.\"\ + },\ + \"ListIdentitiesResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"An identity pool ID in the format REGION:GUID.\"\ + },\ + \"Identities\":{\ + \"shape\":\"IdentitiesList\",\ + \"documentation\":\"An object containing a set of identities and associated mappings.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"A pagination token.\"\ + }\ + },\ + \"documentation\":\"The response to a ListIdentities request.\"\ + },\ + \"ListIdentityPoolsInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"MaxResults\"],\ + \"members\":{\ + \"MaxResults\":{\ + \"shape\":\"QueryLimit\",\ + \"documentation\":\"The maximum number of identities to return.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"A pagination token.\"\ + }\ + },\ + \"documentation\":\"Input to the ListIdentityPools action.\"\ + },\ + \"ListIdentityPoolsResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityPools\":{\ + \"shape\":\"IdentityPoolsList\",\ + \"documentation\":\"The identity pools returned by the ListIdentityPools action.\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"A pagination token.\"\ + }\ + },\ + \"documentation\":\"The result of a successful ListIdentityPools action.\"\ + },\ + \"LoginsList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"IdentityProviderName\"}\ + },\ + \"LoginsMap\":{\ + \"type\":\"map\",\ + \"key\":{\"shape\":\"IdentityProviderName\"},\ + \"value\":{\"shape\":\"IdentityProviderToken\"},\ + \"max\":10\ + },\ + \"LookupDeveloperIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\"IdentityPoolId\"],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + },\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"DeveloperUserIdentifier\":{\ + \"shape\":\"DeveloperUserIdentifier\",\ + \"documentation\":\"

A unique ID used by your backend authentication process to identify a user. Typically, a developer identity provider would issue many developer user identifiers, in keeping with the number of users.

\"\ + },\ + \"MaxResults\":{\ + \"shape\":\"QueryLimit\",\ + \"documentation\":\"

The maximum number of identities to return.

\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"

A pagination token. The first call you make will have NextToken set to null. After that the service will return NextToken values as needed. For example, let's say you make a request with MaxResults set to 10, and there are 20 matches in the database. The service will return a pagination token as a part of the response. This token can be used to call the API again and get results starting from the 11th match.

\"\ + }\ + },\ + \"documentation\":\"

Input to the LookupDeveloperIdentityInput action.

\"\ + },\ + \"LookupDeveloperIdentityResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"DeveloperUserIdentifierList\":{\ + \"shape\":\"DeveloperUserIdentifierList\",\ + \"documentation\":\"

This is the list of developer user identifiers associated with an identity ID. Cognito supports the association of multiple developer user identifiers with an identity ID.

\"\ + },\ + \"NextToken\":{\ + \"shape\":\"PaginationKey\",\ + \"documentation\":\"

A pagination token. The first call you make will have NextToken set to null. After that the service will return NextToken values as needed. For example, let's say you make a request with MaxResults set to 10, and there are 20 matches in the database. The service will return a pagination token as a part of the response. This token can be used to call the API again and get results starting from the 11th match.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful LookupDeveloperIdentity action.

\"\ + },\ + \"MergeDeveloperIdentitiesInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"SourceUserIdentifier\",\ + \"DestinationUserIdentifier\",\ + \"DeveloperProviderName\",\ + \"IdentityPoolId\"\ + ],\ + \"members\":{\ + \"SourceUserIdentifier\":{\ + \"shape\":\"DeveloperUserIdentifier\",\ + \"documentation\":\"

User identifier for the source user. The value should be a DeveloperUserIdentifier.

\"\ + },\ + \"DestinationUserIdentifier\":{\ + \"shape\":\"DeveloperUserIdentifier\",\ + \"documentation\":\"

User identifier for the destination user. The value should be a DeveloperUserIdentifier.

\"\ + },\ + \"DeveloperProviderName\":{\ + \"shape\":\"DeveloperProviderName\",\ + \"documentation\":\"

The \\\"domain\\\" by which Cognito will refer to your users. This is a (pseudo) domain name that you provide while creating an identity pool. This name acts as a placeholder that allows your backend and the Cognito service to communicate about the developer provider. For the DeveloperProviderName, you can use letters as well as period (.), underscore (_), and dash (-).

\"\ + },\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + }\ + },\ + \"documentation\":\"

Input to the MergeDeveloperIdentities action.

\"\ + },\ + \"MergeDeveloperIdentitiesResponse\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + }\ + },\ + \"documentation\":\"

Returned in response to a successful MergeDeveloperIdentities action.

\"\ + },\ + \"NotAuthorizedException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by a NotAuthorizedException\"\ + }\ + },\ + \"documentation\":\"Thrown when a user is not authorized to access the requested resource.\",\ + \"exception\":true\ + },\ + \"OIDCProviderList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"ARNString\"}\ + },\ + \"OIDCToken\":{\"type\":\"string\"},\ + \"PaginationKey\":{\ + \"type\":\"string\",\ + \"min\":1,\ + \"pattern\":\"[\\\\S]+\"\ + },\ + \"QueryLimit\":{\ + \"type\":\"integer\",\ + \"max\":60,\ + \"min\":1\ + },\ + \"ResourceConflictException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by a ResourceConflictException.\"\ + }\ + },\ + \"documentation\":\"Thrown when a user tries to use a login which is already linked to another account.\",\ + \"exception\":true\ + },\ + \"ResourceNotFoundException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"The message returned by a ResourceNotFoundException.\"\ + }\ + },\ + \"documentation\":\"Thrown when the requested resource (for example, a dataset or record) does not exist.\",\ + \"exception\":true\ + },\ + \"RoleType\":{\ + \"type\":\"string\",\ + \"pattern\":\"(un)?authenticated\"\ + },\ + \"RolesMap\":{\ + \"type\":\"map\",\ + \"key\":{\"shape\":\"RoleType\"},\ + \"value\":{\"shape\":\"ARNString\"},\ + \"max\":2\ + },\ + \"SAMLProviderList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"ARNString\"}\ + },\ + \"SecretKeyString\":{\"type\":\"string\"},\ + \"SessionTokenString\":{\"type\":\"string\"},\ + \"SetIdentityPoolRolesInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityPoolId\",\ + \"Roles\"\ + ],\ + \"members\":{\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + },\ + \"Roles\":{\ + \"shape\":\"RolesMap\",\ + \"documentation\":\"

The map of roles associated with this pool. For a given role, the key will be either \\\"authenticated\\\" or \\\"unauthenticated\\\" and the value will be the Role ARN.

\"\ + }\ + },\ + \"documentation\":\"

Input to the SetIdentityPoolRoles action.

\"\ + },\ + \"String\":{\"type\":\"string\"},\ + \"TokenDuration\":{\ + \"type\":\"long\",\ + \"max\":86400,\ + \"min\":1\ + },\ + \"TooManyRequestsException\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"message\":{\ + \"shape\":\"String\",\ + \"documentation\":\"Message returned by a TooManyRequestsException\"\ + }\ + },\ + \"documentation\":\"Thrown when a request is throttled.\",\ + \"exception\":true\ + },\ + \"UnlinkDeveloperIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityId\",\ + \"IdentityPoolId\",\ + \"DeveloperProviderName\",\ + \"DeveloperUserIdentifier\"\ + ],\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"IdentityPoolId\":{\ + \"shape\":\"IdentityPoolId\",\ + \"documentation\":\"

An identity pool ID in the format REGION:GUID.

\"\ + },\ + \"DeveloperProviderName\":{\ + \"shape\":\"DeveloperProviderName\",\ + \"documentation\":\"

The \\\"domain\\\" by which Cognito will refer to your users.

\"\ + },\ + \"DeveloperUserIdentifier\":{\ + \"shape\":\"DeveloperUserIdentifier\",\ + \"documentation\":\"A unique ID used by your backend authentication process to identify a user.\"\ + }\ + },\ + \"documentation\":\"

Input to the UnlinkDeveloperIdentity action.

\"\ + },\ + \"UnlinkIdentityInput\":{\ + \"type\":\"structure\",\ + \"required\":[\ + \"IdentityId\",\ + \"Logins\",\ + \"LoginsToRemove\"\ + ],\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"A unique identifier in the format REGION:GUID.\"\ + },\ + \"Logins\":{\ + \"shape\":\"LoginsMap\",\ + \"documentation\":\"A set of optional name-value pairs that map provider names to provider tokens.\"\ + },\ + \"LoginsToRemove\":{\ + \"shape\":\"LoginsList\",\ + \"documentation\":\"Provider names to unlink from this identity.\"\ + }\ + },\ + \"documentation\":\"Input to the UnlinkIdentity action.\"\ + },\ + \"UnprocessedIdentityId\":{\ + \"type\":\"structure\",\ + \"members\":{\ + \"IdentityId\":{\ + \"shape\":\"IdentityId\",\ + \"documentation\":\"

A unique identifier in the format REGION:GUID.

\"\ + },\ + \"ErrorCode\":{\ + \"shape\":\"ErrorCode\",\ + \"documentation\":\"

The error code indicating the type of error that occurred.

\"\ + }\ + },\ + \"documentation\":\"

An array of UnprocessedIdentityId objects, each of which contains an ErrorCode and IdentityId.

\"\ + },\ + \"UnprocessedIdentityIdList\":{\ + \"type\":\"list\",\ + \"member\":{\"shape\":\"UnprocessedIdentityId\"},\ + \"max\":60\ + }\ + },\ + \"documentation\":\"Amazon Cognito

Amazon Cognito is a web service that delivers scoped temporary credentials to mobile devices and other untrusted environments. Amazon Cognito uniquely identifies a device and supplies the user with a consistent identity over the lifetime of an application.

Using Amazon Cognito, you can enable authentication with one or more third-party identity providers (Facebook, Google, or Login with Amazon), and you can also choose to support unauthenticated access from your app. Cognito delivers a unique identifier for each user and acts as an OpenID token provider trusted by AWS Security Token Service (STS) to access temporary, limited-privilege AWS credentials.

To provide end-user credentials, first make an unsigned call to GetId. If the end user is authenticated with one of the supported identity providers, set the Logins map with the identity provider token. GetId returns a unique identifier for the user.

Next, make an unsigned call to GetCredentialsForIdentity. This call expects the same Logins map as the GetId call, as well as the IdentityID originally returned by GetId. Assuming your identity pool has been configured via the SetIdentityPoolRoles operation, GetCredentialsForIdentity will return AWS credentials for your use. If your pool has not been configured with SetIdentityPoolRoles, or if you want to follow legacy flow, make an unsigned call to GetOpenIdToken, which returns the OpenID token necessary to call STS and retrieve AWS credentials. This call expects the same Logins map as the GetId call, as well as the IdentityID originally returned by GetId. The token returned by GetOpenIdToken can be passed to the STS operation AssumeRoleWithWebIdentity to retrieve AWS credentials.

If you want to use Amazon Cognito in an Android, iOS, or Unity application, you will probably want to make API calls via the AWS Mobile SDK. To learn more, see the AWS Mobile SDK Developer Guide.

\"\ +}\ +"; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.h b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.h new file mode 100644 index 00000000..6ecea7b9 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.h @@ -0,0 +1,614 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import "AWSCore.h" +#import "AWSCognitoIdentityModel.h" +#import "AWSCognitoIdentityResources.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Amazon Cognito

Amazon Cognito is a web service that delivers scoped temporary credentials to mobile devices and other untrusted environments. Amazon Cognito uniquely identifies a device and supplies the user with a consistent identity over the lifetime of an application.

Using Amazon Cognito, you can enable authentication with one or more third-party identity providers (Facebook, Google, or Login with Amazon), and you can also choose to support unauthenticated access from your app. Cognito delivers a unique identifier for each user and acts as an OpenID token provider trusted by AWS Security Token Service (STS) to access temporary, limited-privilege AWS credentials.

To provide end-user credentials, first make an unsigned call to GetId. If the end user is authenticated with one of the supported identity providers, set the Logins map with the identity provider token. GetId returns a unique identifier for the user.

Next, make an unsigned call to GetCredentialsForIdentity. This call expects the same Logins map as the GetId call, as well as the IdentityID originally returned by GetId. Assuming your identity pool has been configured via the SetIdentityPoolRoles operation, GetCredentialsForIdentity will return AWS credentials for your use. If your pool has not been configured with SetIdentityPoolRoles, or if you want to follow legacy flow, make an unsigned call to GetOpenIdToken, which returns the OpenID token necessary to call STS and retrieve AWS credentials. This call expects the same Logins map as the GetId call, as well as the IdentityID originally returned by GetId. The token returned by GetOpenIdToken can be passed to the STS operation AssumeRoleWithWebIdentity to retrieve AWS credentials.

If you want to use Amazon Cognito in an Android, iOS, or Unity application, you will probably want to make API calls via the AWS Mobile SDK. To learn more, see the AWS Mobile SDK Developer Guide.

+ */ +@interface AWSCognitoIdentity : AWSService + +/** + The service configuration used to instantiate this service client. + + @warning Once the client is instantiated, do not modify the configuration object. It may cause unspecified behaviors. + */ +@property (nonatomic, strong, readonly) AWSServiceConfiguration *configuration; + +/** + Returns the singleton service client. If the singleton object does not exist, the SDK instantiates the default service client with `defaultServiceConfiguration` from `[AWSServiceManager defaultServiceManager]`. The reference to this object is maintained by the SDK, and you do not need to retain it manually. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialProvider) + AWSServiceManager.default().defaultServiceConfiguration = configuration + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 + credentialsProvider:credentialsProvider]; + [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration; + + return YES; + } + + Then call the following to get the default service client: + + *Swift* + + let CognitoIdentity = AWSCognitoIdentity.default() + + *Objective-C* + + AWSCognitoIdentity *CognitoIdentity = [AWSCognitoIdentity defaultCognitoIdentity]; + + @return The default service client. + */ ++ (instancetype)defaultCognitoIdentity; + +/** + Creates a service client with the given service configuration and registers it for the key. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognitoIdentity.register(with: configuration!, forKey: "USWest2CognitoIdentity") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognitoIdentity registerCognitoIdentityWithConfiguration:configuration forKey:@"USWest2CognitoIdentity"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let CognitoIdentity = AWSCognitoIdentity(forKey: "USWest2CognitoIdentity") + + *Objective-C* + + AWSCognitoIdentity *CognitoIdentity = [AWSCognitoIdentity CognitoIdentityForKey:@"USWest2CognitoIdentity"]; + + @warning After calling this method, do not modify the configuration object. It may cause unspecified behaviors. + + @param configuration A service configuration object. + @param key A string to identify the service client. + */ ++ (void)registerCognitoIdentityWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key; + +/** + Retrieves the service client associated with the key. You need to call `+ registerCognitoIdentityWithConfiguration:forKey:` before invoking this method. + + For example, set the default service configuration in `- application:didFinishLaunchingWithOptions:` + + *Swift* + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") + let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) + AWSCognitoIdentity.register(with: configuration!, forKey: "USWest2CognitoIdentity") + + return true + } + + *Objective-C* + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 + identityPoolId:@"YourIdentityPoolId"]; + AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 + credentialsProvider:credentialsProvider]; + + [AWSCognitoIdentity registerCognitoIdentityWithConfiguration:configuration forKey:@"USWest2CognitoIdentity"]; + + return YES; + } + + Then call the following to get the service client: + + *Swift* + + let CognitoIdentity = AWSCognitoIdentity(forKey: "USWest2CognitoIdentity") + + *Objective-C* + + AWSCognitoIdentity *CognitoIdentity = [AWSCognitoIdentity CognitoIdentityForKey:@"USWest2CognitoIdentity"]; + + @param key A string to identify the service client. + + @return An instance of the service client. + */ ++ (instancetype)CognitoIdentityForKey:(NSString *)key; + +/** + Removes the service client associated with the key and release it. + + @warning Before calling this method, make sure no method is running on this client. + + @param key A string to identify the service client. + */ ++ (void)removeCognitoIdentityForKey:(NSString *)key; + +/** +

Creates a new identity pool. The identity pool is a store of user identity information that is specific to your AWS account. The limit on identity pools is 60 per account. The keys for SupportedLoginProviders are as follows:

  • Facebook: graph.facebook.com
  • Google: accounts.google.com
  • Amazon: www.amazon.com
  • Twitter: api.twitter.com
  • Digits: www.digits.com
You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the CreateIdentityPool service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityIdentityPool`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorLimitExceeded`. + + @see AWSCognitoIdentityCreateIdentityPoolInput + @see AWSCognitoIdentityIdentityPool + */ +- (AWSTask *)createIdentityPool:(AWSCognitoIdentityCreateIdentityPoolInput *)request; + +/** +

Creates a new identity pool. The identity pool is a store of user identity information that is specific to your AWS account. The limit on identity pools is 60 per account. The keys for SupportedLoginProviders are as follows:

  • Facebook: graph.facebook.com
  • Google: accounts.google.com
  • Amazon: www.amazon.com
  • Twitter: api.twitter.com
  • Digits: www.digits.com
You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the CreateIdentityPool service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorLimitExceeded`. + + @see AWSCognitoIdentityCreateIdentityPoolInput + @see AWSCognitoIdentityIdentityPool + */ +- (void)createIdentityPool:(AWSCognitoIdentityCreateIdentityPoolInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityIdentityPool * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Deletes identities from an identity pool. You can specify a list of 1-60 identities that you want to delete.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DeleteIdentities service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityDeleteIdentitiesResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDeleteIdentitiesInput + @see AWSCognitoIdentityDeleteIdentitiesResponse + */ +- (AWSTask *)deleteIdentities:(AWSCognitoIdentityDeleteIdentitiesInput *)request; + +/** +

Deletes identities from an identity pool. You can specify a list of 1-60 identities that you want to delete.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DeleteIdentities service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDeleteIdentitiesInput + @see AWSCognitoIdentityDeleteIdentitiesResponse + */ +- (void)deleteIdentities:(AWSCognitoIdentityDeleteIdentitiesInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityDeleteIdentitiesResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Deletes a user pool. Once a pool is deleted, users will not be able to authenticate with the pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DeleteIdentityPool service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will be `nil`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDeleteIdentityPoolInput + */ +- (AWSTask *)deleteIdentityPool:(AWSCognitoIdentityDeleteIdentityPoolInput *)request; + +/** +

Deletes a user pool. Once a pool is deleted, users will not be able to authenticate with the pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DeleteIdentityPool service method. + @param completionHandler The completion handler to call when the load request is complete. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDeleteIdentityPoolInput + */ +- (void)deleteIdentityPool:(AWSCognitoIdentityDeleteIdentityPoolInput *)request completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler; + +/** +

Returns metadata related to the given identity, including when the identity was created and any associated linked logins.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DescribeIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityIdentityDescription`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDescribeIdentityInput + @see AWSCognitoIdentityIdentityDescription + */ +- (AWSTask *)describeIdentity:(AWSCognitoIdentityDescribeIdentityInput *)request; + +/** +

Returns metadata related to the given identity, including when the identity was created and any associated linked logins.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DescribeIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDescribeIdentityInput + @see AWSCognitoIdentityIdentityDescription + */ +- (void)describeIdentity:(AWSCognitoIdentityDescribeIdentityInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityIdentityDescription * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets details about a particular identity pool, including the pool name, ID description, creation date, and current number of users.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityPool service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityIdentityPool`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDescribeIdentityPoolInput + @see AWSCognitoIdentityIdentityPool + */ +- (AWSTask *)describeIdentityPool:(AWSCognitoIdentityDescribeIdentityPoolInput *)request; + +/** +

Gets details about a particular identity pool, including the pool name, ID description, creation date, and current number of users.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the DescribeIdentityPool service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityDescribeIdentityPoolInput + @see AWSCognitoIdentityIdentityPool + */ +- (void)describeIdentityPool:(AWSCognitoIdentityDescribeIdentityPoolInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityIdentityPool * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Returns credentials for the provided identity ID. Any provided logins will be validated against supported login providers. If the token is for cognito-identity.amazonaws.com, it will be passed through to AWS Security Token Service with the appropriate role for the token.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetCredentialsForIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityGetCredentialsForIdentityResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInvalidIdentityPoolConfiguration`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetCredentialsForIdentityInput + @see AWSCognitoIdentityGetCredentialsForIdentityResponse + */ +- (AWSTask *)getCredentialsForIdentity:(AWSCognitoIdentityGetCredentialsForIdentityInput *)request; + +/** +

Returns credentials for the provided identity ID. Any provided logins will be validated against supported login providers. If the token is for cognito-identity.amazonaws.com, it will be passed through to AWS Security Token Service with the appropriate role for the token.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetCredentialsForIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInvalidIdentityPoolConfiguration`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetCredentialsForIdentityInput + @see AWSCognitoIdentityGetCredentialsForIdentityResponse + */ +- (void)getCredentialsForIdentity:(AWSCognitoIdentityGetCredentialsForIdentityInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityGetCredentialsForIdentityResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Generates (or retrieves) a Cognito ID. Supplying multiple logins will create an implicit linked account.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetId service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityGetIdResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorLimitExceeded`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetIdInput + @see AWSCognitoIdentityGetIdResponse + */ +- (AWSTask *)getId:(AWSCognitoIdentityGetIdInput *)request; + +/** +

Generates (or retrieves) a Cognito ID. Supplying multiple logins will create an implicit linked account.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetId service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorLimitExceeded`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetIdInput + @see AWSCognitoIdentityGetIdResponse + */ +- (void)getId:(AWSCognitoIdentityGetIdInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityGetIdResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets the roles for an identity pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetIdentityPoolRoles service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityGetIdentityPoolRolesResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityGetIdentityPoolRolesInput + @see AWSCognitoIdentityGetIdentityPoolRolesResponse + */ +- (AWSTask *)getIdentityPoolRoles:(AWSCognitoIdentityGetIdentityPoolRolesInput *)request; + +/** +

Gets the roles for an identity pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetIdentityPoolRoles service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityGetIdentityPoolRolesInput + @see AWSCognitoIdentityGetIdentityPoolRolesResponse + */ +- (void)getIdentityPoolRoles:(AWSCognitoIdentityGetIdentityPoolRolesInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityGetIdentityPoolRolesResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Gets an OpenID token, using a known Cognito ID. This known Cognito ID is returned by GetId. You can optionally add additional logins for the identity. Supplying multiple logins creates an implicit link.

The OpenId token is valid for 15 minutes.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetOpenIdToken service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityGetOpenIdTokenResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetOpenIdTokenInput + @see AWSCognitoIdentityGetOpenIdTokenResponse + */ +- (AWSTask *)getOpenIdToken:(AWSCognitoIdentityGetOpenIdTokenInput *)request; + +/** +

Gets an OpenID token, using a known Cognito ID. This known Cognito ID is returned by GetId. You can optionally add additional logins for the identity. Supplying multiple logins creates an implicit link.

The OpenId token is valid for 15 minutes.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetOpenIdToken service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityGetOpenIdTokenInput + @see AWSCognitoIdentityGetOpenIdTokenResponse + */ +- (void)getOpenIdToken:(AWSCognitoIdentityGetOpenIdTokenInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityGetOpenIdTokenResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Registers (or retrieves) a Cognito IdentityId and an OpenID Connect token for a user authenticated by your backend authentication process. Supplying multiple logins will create an implicit linked account. You can only specify one developer provider as part of the Logins map, which is linked to the identity pool. The developer provider is the "domain" by which Cognito will refer to your users.

You can use GetOpenIdTokenForDeveloperIdentity to create a new identity and to link new logins (that is, user credentials issued by a public provider or developer provider) to an existing identity. When you want to create a new identity, the IdentityId should be null. When you want to associate a new login with an existing authenticated/unauthenticated identity, you can do so by providing the existing IdentityId. This API will create the identity in the specified IdentityPoolId.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetOpenIdTokenForDeveloperIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorDeveloperUserAlreadyRegistered`. + + @see AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput + @see AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse + */ +- (AWSTask *)getOpenIdTokenForDeveloperIdentity:(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput *)request; + +/** +

Registers (or retrieves) a Cognito IdentityId and an OpenID Connect token for a user authenticated by your backend authentication process. Supplying multiple logins will create an implicit linked account. You can only specify one developer provider as part of the Logins map, which is linked to the identity pool. The developer provider is the "domain" by which Cognito will refer to your users.

You can use GetOpenIdTokenForDeveloperIdentity to create a new identity and to link new logins (that is, user credentials issued by a public provider or developer provider) to an existing identity. When you want to create a new identity, the IdentityId should be null. When you want to associate a new login with an existing authenticated/unauthenticated identity, you can do so by providing the existing IdentityId. This API will create the identity in the specified IdentityPoolId.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the GetOpenIdTokenForDeveloperIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorDeveloperUserAlreadyRegistered`. + + @see AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput + @see AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse + */ +- (void)getOpenIdTokenForDeveloperIdentity:(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Lists the identities in a pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the ListIdentities service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityListIdentitiesResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityListIdentitiesInput + @see AWSCognitoIdentityListIdentitiesResponse + */ +- (AWSTask *)listIdentities:(AWSCognitoIdentityListIdentitiesInput *)request; + +/** +

Lists the identities in a pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the ListIdentities service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityListIdentitiesInput + @see AWSCognitoIdentityListIdentitiesResponse + */ +- (void)listIdentities:(AWSCognitoIdentityListIdentitiesInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityListIdentitiesResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Lists all of the Cognito identity pools registered for your account.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the ListIdentityPools service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityListIdentityPoolsResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityListIdentityPoolsInput + @see AWSCognitoIdentityListIdentityPoolsResponse + */ +- (AWSTask *)listIdentityPools:(AWSCognitoIdentityListIdentityPoolsInput *)request; + +/** +

Lists all of the Cognito identity pools registered for your account.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the ListIdentityPools service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityListIdentityPoolsInput + @see AWSCognitoIdentityListIdentityPoolsResponse + */ +- (void)listIdentityPools:(AWSCognitoIdentityListIdentityPoolsInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityListIdentityPoolsResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Retrieves the IdentityID associated with a DeveloperUserIdentifier or the list of DeveloperUserIdentifiers associated with an IdentityId for an existing identity. Either IdentityID or DeveloperUserIdentifier must not be null. If you supply only one of these values, the other value will be searched in the database and returned as a part of the response. If you supply both, DeveloperUserIdentifier will be matched against IdentityID. If the values are verified against the database, the response returns both values and is the same as the request. Otherwise a ResourceConflictException is thrown.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the LookupDeveloperIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityLookupDeveloperIdentityResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityLookupDeveloperIdentityInput + @see AWSCognitoIdentityLookupDeveloperIdentityResponse + */ +- (AWSTask *)lookupDeveloperIdentity:(AWSCognitoIdentityLookupDeveloperIdentityInput *)request; + +/** +

Retrieves the IdentityID associated with a DeveloperUserIdentifier or the list of DeveloperUserIdentifiers associated with an IdentityId for an existing identity. Either IdentityID or DeveloperUserIdentifier must not be null. If you supply only one of these values, the other value will be searched in the database and returned as a part of the response. If you supply both, DeveloperUserIdentifier will be matched against IdentityID. If the values are verified against the database, the response returns both values and is the same as the request. Otherwise a ResourceConflictException is thrown.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the LookupDeveloperIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityLookupDeveloperIdentityInput + @see AWSCognitoIdentityLookupDeveloperIdentityResponse + */ +- (void)lookupDeveloperIdentity:(AWSCognitoIdentityLookupDeveloperIdentityInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityLookupDeveloperIdentityResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Merges two users having different IdentityIds, existing in the same identity pool, and identified by the same developer provider. You can use this action to request that discrete users be merged and identified as a single user in the Cognito environment. Cognito associates the given source user (SourceUserIdentifier) with the IdentityId of the DestinationUserIdentifier. Only developer-authenticated users can be merged. If the users to be merged are associated with the same public provider, but as two different users, an exception will be thrown.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the MergeDeveloperIdentities service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityMergeDeveloperIdentitiesResponse`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityMergeDeveloperIdentitiesInput + @see AWSCognitoIdentityMergeDeveloperIdentitiesResponse + */ +- (AWSTask *)mergeDeveloperIdentities:(AWSCognitoIdentityMergeDeveloperIdentitiesInput *)request; + +/** +

Merges two users having different IdentityIds, existing in the same identity pool, and identified by the same developer provider. You can use this action to request that discrete users be merged and identified as a single user in the Cognito environment. Cognito associates the given source user (SourceUserIdentifier) with the IdentityId of the DestinationUserIdentifier. Only developer-authenticated users can be merged. If the users to be merged are associated with the same public provider, but as two different users, an exception will be thrown.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the MergeDeveloperIdentities service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityMergeDeveloperIdentitiesInput + @see AWSCognitoIdentityMergeDeveloperIdentitiesResponse + */ +- (void)mergeDeveloperIdentities:(AWSCognitoIdentityMergeDeveloperIdentitiesInput *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityMergeDeveloperIdentitiesResponse * _Nullable response, NSError * _Nullable error))completionHandler; + +/** +

Sets the roles for an identity pool. These roles are used when making calls to GetCredentialsForIdentity action.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the SetIdentityPoolRoles service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will be `nil`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorConcurrentModification`. + + @see AWSCognitoIdentitySetIdentityPoolRolesInput + */ +- (AWSTask *)setIdentityPoolRoles:(AWSCognitoIdentitySetIdentityPoolRolesInput *)request; + +/** +

Sets the roles for an identity pool. These roles are used when making calls to GetCredentialsForIdentity action.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the SetIdentityPoolRoles service method. + @param completionHandler The completion handler to call when the load request is complete. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorConcurrentModification`. + + @see AWSCognitoIdentitySetIdentityPoolRolesInput + */ +- (void)setIdentityPoolRoles:(AWSCognitoIdentitySetIdentityPoolRolesInput *)request completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler; + +/** +

Unlinks a DeveloperUserIdentifier from an existing identity. Unlinked developer users will be considered new identities next time they are seen. If, for a given Cognito identity, you remove all federated identities as well as the developer user identifier, the Cognito identity becomes inaccessible.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UnlinkDeveloperIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will be `nil`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityUnlinkDeveloperIdentityInput + */ +- (AWSTask *)unlinkDeveloperIdentity:(AWSCognitoIdentityUnlinkDeveloperIdentityInput *)request; + +/** +

Unlinks a DeveloperUserIdentifier from an existing identity. Unlinked developer users will be considered new identities next time they are seen. If, for a given Cognito identity, you remove all federated identities as well as the developer user identifier, the Cognito identity becomes inaccessible.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UnlinkDeveloperIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`. + + @see AWSCognitoIdentityUnlinkDeveloperIdentityInput + */ +- (void)unlinkDeveloperIdentity:(AWSCognitoIdentityUnlinkDeveloperIdentityInput *)request completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler; + +/** +

Unlinks a federated identity from an existing account. Unlinked logins will be considered new identities next time they are seen. Removing the last linked login will make this identity inaccessible.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UnlinkIdentity service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will be `nil`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityUnlinkIdentityInput + */ +- (AWSTask *)unlinkIdentity:(AWSCognitoIdentityUnlinkIdentityInput *)request; + +/** +

Unlinks a federated identity from an existing account. Unlinked logins will be considered new identities next time they are seen. Removing the last linked login will make this identity inaccessible.

This is a public API. You do not need any credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UnlinkIdentity service method. + @param completionHandler The completion handler to call when the load request is complete. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorExternalService`. + + @see AWSCognitoIdentityUnlinkIdentityInput + */ +- (void)unlinkIdentity:(AWSCognitoIdentityUnlinkIdentityInput *)request completionHandler:(void (^ _Nullable)(NSError * _Nullable error))completionHandler; + +/** +

Updates a user pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UpdateIdentityPool service method. + + @return An instance of `AWSTask`. On successful execution, `task.result` will contain an instance of `AWSCognitoIdentityIdentityPool`. On failed execution, `task.error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorConcurrentModification`, `AWSCognitoIdentityErrorLimitExceeded`. + + @see AWSCognitoIdentityIdentityPool + @see AWSCognitoIdentityIdentityPool + */ +- (AWSTask *)updateIdentityPool:(AWSCognitoIdentityIdentityPool *)request; + +/** +

Updates a user pool.

You must use AWS Developer credentials to call this API.

+ + @param request A container for the necessary parameters to execute the UpdateIdentityPool service method. + @param completionHandler The completion handler to call when the load request is complete. + `response` - A response object, or `nil` if the request failed. + `error` - An error object that indicates why the request failed, or `nil` if the request was successful. On failed execution, `error` may contain an `NSError` with `AWSCognitoIdentityErrorDomain` domain and the following error code: `AWSCognitoIdentityErrorInvalidParameter`, `AWSCognitoIdentityErrorResourceNotFound`, `AWSCognitoIdentityErrorNotAuthorized`, `AWSCognitoIdentityErrorResourceConflict`, `AWSCognitoIdentityErrorTooManyRequests`, `AWSCognitoIdentityErrorInternalError`, `AWSCognitoIdentityErrorConcurrentModification`, `AWSCognitoIdentityErrorLimitExceeded`. + + @see AWSCognitoIdentityIdentityPool + @see AWSCognitoIdentityIdentityPool + */ +- (void)updateIdentityPool:(AWSCognitoIdentityIdentityPool *)request completionHandler:(void (^ _Nullable)(AWSCognitoIdentityIdentityPool * _Nullable response, NSError * _Nullable error))completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m new file mode 100644 index 00000000..70584c30 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m @@ -0,0 +1,689 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoIdentityService.h" +#import "AWSNetworking.h" +#import "AWSCategory.h" +#import "AWSNetworking.h" +#import "AWSSignature.h" +#import "AWSService.h" +#import "AWSURLRequestSerialization.h" +#import "AWSURLResponseSerialization.h" +#import "AWSURLRequestRetryHandler.h" +#import "AWSSynchronizedMutableDictionary.h" +#import "AWSCognitoIdentityResources.h" + +static NSString *const AWSInfoCognitoIdentity = @"CognitoIdentity"; + + +@interface AWSCognitoIdentityResponseSerializer : AWSJSONResponseSerializer + +@end + +@implementation AWSCognitoIdentityResponseSerializer + +#pragma mark - Service errors + +static NSDictionary *errorCodeDictionary = nil; ++ (void)initialize { + errorCodeDictionary = @{ + @"ConcurrentModificationException" : @(AWSCognitoIdentityErrorConcurrentModification), + @"DeveloperUserAlreadyRegisteredException" : @(AWSCognitoIdentityErrorDeveloperUserAlreadyRegistered), + @"ExternalServiceException" : @(AWSCognitoIdentityErrorExternalService), + @"InternalErrorException" : @(AWSCognitoIdentityErrorInternalError), + @"InvalidIdentityPoolConfigurationException" : @(AWSCognitoIdentityErrorInvalidIdentityPoolConfiguration), + @"InvalidParameterException" : @(AWSCognitoIdentityErrorInvalidParameter), + @"LimitExceededException" : @(AWSCognitoIdentityErrorLimitExceeded), + @"NotAuthorizedException" : @(AWSCognitoIdentityErrorNotAuthorized), + @"ResourceConflictException" : @(AWSCognitoIdentityErrorResourceConflict), + @"ResourceNotFoundException" : @(AWSCognitoIdentityErrorResourceNotFound), + @"TooManyRequestsException" : @(AWSCognitoIdentityErrorTooManyRequests), + }; +} + +#pragma mark - + +- (id)responseObjectForResponse:(NSHTTPURLResponse *)response + originalRequest:(NSURLRequest *)originalRequest + currentRequest:(NSURLRequest *)currentRequest + data:(id)data + error:(NSError *__autoreleasing *)error { + id responseObject = [super responseObjectForResponse:response + originalRequest:originalRequest + currentRequest:currentRequest + data:data + error:error]; + if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { + if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { + if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { + if (error) { + *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain + code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] + userInfo:responseObject]; + } + return responseObject; + } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { + if (error) { + *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain + code:AWSCognitoIdentityErrorUnknown + userInfo:responseObject]; + } + return responseObject; + } + } + } + + if (!*error && response.statusCode/100 != 2) { + *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain + code:AWSCognitoIdentityErrorUnknown + userInfo:nil]; + } + + if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { + if (self.outputClass) { + responseObject = [AWSMTLJSONAdapter modelOfClass:self.outputClass + fromJSONDictionary:responseObject + error:error]; + } + } + return responseObject; +} + +@end + +@interface AWSCognitoIdentityRequestRetryHandler : AWSURLRequestRetryHandler + +@end + +@implementation AWSCognitoIdentityRequestRetryHandler + +@end + +@interface AWSRequest() + +@property (nonatomic, strong) AWSNetworkingRequest *internalRequest; + +@end + +@interface AWSCognitoIdentity() + +@property (nonatomic, strong) AWSNetworking *networking; +@property (nonatomic, strong) AWSServiceConfiguration *configuration; + +@end + +@interface AWSServiceConfiguration() + +@property (nonatomic, strong) AWSEndpoint *endpoint; + +@end + +@interface AWSEndpoint() + +- (void) setRegion:(AWSRegionType)regionType service:(AWSServiceType)serviceType; + +@end + +@implementation AWSCognitoIdentity + + +#pragma mark - Setup + +static AWSSynchronizedMutableDictionary *_serviceClients = nil; + ++ (instancetype)defaultCognitoIdentity { + static AWSCognitoIdentity *_defaultCognitoIdentity = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AWSServiceConfiguration *serviceConfiguration = nil; + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoCognitoIdentity]; + if (serviceInfo) { + serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + } + + if (!serviceConfiguration) { + serviceConfiguration = [AWSServiceManager defaultServiceManager].defaultServiceConfiguration; + } + + if (!serviceConfiguration) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method." + userInfo:nil]; + } + _defaultCognitoIdentity = [[AWSCognitoIdentity alloc] initWithConfiguration:serviceConfiguration]; + }); + + return _defaultCognitoIdentity; +} + ++ (void)registerCognitoIdentityWithConfiguration:(AWSServiceConfiguration *)configuration forKey:(NSString *)key { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _serviceClients = [AWSSynchronizedMutableDictionary new]; + }); + [_serviceClients setObject:[[AWSCognitoIdentity alloc] initWithConfiguration:configuration] + forKey:key]; +} + ++ (instancetype)CognitoIdentityForKey:(NSString *)key { + @synchronized(self) { + AWSCognitoIdentity *serviceClient = [_serviceClients objectForKey:key]; + if (serviceClient) { + return serviceClient; + } + + AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoCognitoIdentity + forKey:key]; + if (serviceInfo) { + AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + [AWSCognitoIdentity registerCognitoIdentityWithConfiguration:serviceConfiguration + forKey:key]; + } + + return [_serviceClients objectForKey:key]; + } +} + ++ (void)removeCognitoIdentityForKey:(NSString *)key { + [_serviceClients removeObjectForKey:key]; +} + +- (instancetype)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"`- init` is not a valid initializer. Use `+ defaultCognitoIdentity` or `+ CognitoIdentityForKey:` instead." + userInfo:nil]; + return nil; +} + +#pragma mark - + +- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration { + if (self = [super init]) { + _configuration = [configuration copy]; + + if(!configuration.endpoint){ + _configuration.endpoint = [[AWSEndpoint alloc] initWithRegion:_configuration.regionType + service:AWSServiceCognitoIdentity + useUnsafeURL:NO]; + }else{ + [_configuration.endpoint setRegion:_configuration.regionType + service:AWSServiceCognitoIdentity]; + } + + AWSSignatureV4Signer *signer = [[AWSSignatureV4Signer alloc] initWithCredentialsProvider:_configuration.credentialsProvider + endpoint:_configuration.endpoint]; + AWSNetworkingRequestInterceptor *baseInterceptor = [[AWSNetworkingRequestInterceptor alloc] initWithUserAgent:_configuration.userAgent]; + _configuration.requestInterceptors = @[baseInterceptor, signer]; + + _configuration.baseURL = _configuration.endpoint.URL; + _configuration.retryHandler = [[AWSCognitoIdentityRequestRetryHandler alloc] initWithMaximumRetryCount:_configuration.maxRetryCount]; + _configuration.headers = @{@"Content-Type" : @"application/x-amz-json-1.1"}; + + _networking = [[AWSNetworking alloc] initWithConfiguration:_configuration]; + } + + return self; +} + +- (AWSTask *)invokeRequest:(AWSRequest *)request + HTTPMethod:(AWSHTTPMethod)HTTPMethod + URLString:(NSString *) URLString + targetPrefix:(NSString *)targetPrefix + operationName:(NSString *)operationName + outputClass:(Class)outputClass { + + @autoreleasepool { + if (!request) { + request = [AWSRequest new]; + } + + AWSNetworkingRequest *networkingRequest = request.internalRequest; + if (request) { + networkingRequest.parameters = [[AWSMTLJSONAdapter JSONDictionaryFromModel:request] aws_removeNullValues]; + } else { + networkingRequest.parameters = @{}; + } + + NSMutableDictionary *headers = [NSMutableDictionary new]; + headers[@"X-Amz-Target"] = [NSString stringWithFormat:@"%@.%@", targetPrefix, operationName]; + networkingRequest.headers = headers; + networkingRequest.HTTPMethod = HTTPMethod; + networkingRequest.requestSerializer = [[AWSJSONRequestSerializer alloc] initWithJSONDefinition:[[AWSCognitoIdentityResources sharedInstance] JSONObject] + actionName:operationName]; + networkingRequest.responseSerializer = [[AWSCognitoIdentityResponseSerializer alloc] initWithJSONDefinition:[[AWSCognitoIdentityResources sharedInstance] JSONObject] + actionName:operationName + outputClass:outputClass]; + + return [self.networking sendRequest:networkingRequest]; + } +} + +#pragma mark - Service method + +- (AWSTask *)createIdentityPool:(AWSCognitoIdentityCreateIdentityPoolInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"CreateIdentityPool" + outputClass:[AWSCognitoIdentityIdentityPool class]]; +} + +- (void)createIdentityPool:(AWSCognitoIdentityCreateIdentityPoolInput *)request + completionHandler:(void (^)(AWSCognitoIdentityIdentityPool *response, NSError *error))completionHandler { + [[self createIdentityPool:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityIdentityPool *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)deleteIdentities:(AWSCognitoIdentityDeleteIdentitiesInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"DeleteIdentities" + outputClass:[AWSCognitoIdentityDeleteIdentitiesResponse class]]; +} + +- (void)deleteIdentities:(AWSCognitoIdentityDeleteIdentitiesInput *)request + completionHandler:(void (^)(AWSCognitoIdentityDeleteIdentitiesResponse *response, NSError *error))completionHandler { + [[self deleteIdentities:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityDeleteIdentitiesResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)deleteIdentityPool:(AWSCognitoIdentityDeleteIdentityPoolInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"DeleteIdentityPool" + outputClass:nil]; +} + +- (void)deleteIdentityPool:(AWSCognitoIdentityDeleteIdentityPoolInput *)request + completionHandler:(void (^)(NSError *error))completionHandler { + [[self deleteIdentityPool:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSError *error = task.error; + + if (completionHandler) { + completionHandler(error); + } + + return nil; + }]; +} + +- (AWSTask *)describeIdentity:(AWSCognitoIdentityDescribeIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"DescribeIdentity" + outputClass:[AWSCognitoIdentityIdentityDescription class]]; +} + +- (void)describeIdentity:(AWSCognitoIdentityDescribeIdentityInput *)request + completionHandler:(void (^)(AWSCognitoIdentityIdentityDescription *response, NSError *error))completionHandler { + [[self describeIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityIdentityDescription *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)describeIdentityPool:(AWSCognitoIdentityDescribeIdentityPoolInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"DescribeIdentityPool" + outputClass:[AWSCognitoIdentityIdentityPool class]]; +} + +- (void)describeIdentityPool:(AWSCognitoIdentityDescribeIdentityPoolInput *)request + completionHandler:(void (^)(AWSCognitoIdentityIdentityPool *response, NSError *error))completionHandler { + [[self describeIdentityPool:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityIdentityPool *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getCredentialsForIdentity:(AWSCognitoIdentityGetCredentialsForIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"GetCredentialsForIdentity" + outputClass:[AWSCognitoIdentityGetCredentialsForIdentityResponse class]]; +} + +- (void)getCredentialsForIdentity:(AWSCognitoIdentityGetCredentialsForIdentityInput *)request + completionHandler:(void (^)(AWSCognitoIdentityGetCredentialsForIdentityResponse *response, NSError *error))completionHandler { + [[self getCredentialsForIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetCredentialsForIdentityResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getId:(AWSCognitoIdentityGetIdInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"GetId" + outputClass:[AWSCognitoIdentityGetIdResponse class]]; +} + +- (void)getId:(AWSCognitoIdentityGetIdInput *)request + completionHandler:(void (^)(AWSCognitoIdentityGetIdResponse *response, NSError *error))completionHandler { + [[self getId:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetIdResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getIdentityPoolRoles:(AWSCognitoIdentityGetIdentityPoolRolesInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"GetIdentityPoolRoles" + outputClass:[AWSCognitoIdentityGetIdentityPoolRolesResponse class]]; +} + +- (void)getIdentityPoolRoles:(AWSCognitoIdentityGetIdentityPoolRolesInput *)request + completionHandler:(void (^)(AWSCognitoIdentityGetIdentityPoolRolesResponse *response, NSError *error))completionHandler { + [[self getIdentityPoolRoles:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetIdentityPoolRolesResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getOpenIdToken:(AWSCognitoIdentityGetOpenIdTokenInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"GetOpenIdToken" + outputClass:[AWSCognitoIdentityGetOpenIdTokenResponse class]]; +} + +- (void)getOpenIdToken:(AWSCognitoIdentityGetOpenIdTokenInput *)request + completionHandler:(void (^)(AWSCognitoIdentityGetOpenIdTokenResponse *response, NSError *error))completionHandler { + [[self getOpenIdToken:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetOpenIdTokenResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)getOpenIdTokenForDeveloperIdentity:(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"GetOpenIdTokenForDeveloperIdentity" + outputClass:[AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse class]]; +} + +- (void)getOpenIdTokenForDeveloperIdentity:(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityInput *)request + completionHandler:(void (^)(AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse *response, NSError *error))completionHandler { + [[self getOpenIdTokenForDeveloperIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityGetOpenIdTokenForDeveloperIdentityResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)listIdentities:(AWSCognitoIdentityListIdentitiesInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"ListIdentities" + outputClass:[AWSCognitoIdentityListIdentitiesResponse class]]; +} + +- (void)listIdentities:(AWSCognitoIdentityListIdentitiesInput *)request + completionHandler:(void (^)(AWSCognitoIdentityListIdentitiesResponse *response, NSError *error))completionHandler { + [[self listIdentities:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityListIdentitiesResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)listIdentityPools:(AWSCognitoIdentityListIdentityPoolsInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"ListIdentityPools" + outputClass:[AWSCognitoIdentityListIdentityPoolsResponse class]]; +} + +- (void)listIdentityPools:(AWSCognitoIdentityListIdentityPoolsInput *)request + completionHandler:(void (^)(AWSCognitoIdentityListIdentityPoolsResponse *response, NSError *error))completionHandler { + [[self listIdentityPools:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityListIdentityPoolsResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)lookupDeveloperIdentity:(AWSCognitoIdentityLookupDeveloperIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"LookupDeveloperIdentity" + outputClass:[AWSCognitoIdentityLookupDeveloperIdentityResponse class]]; +} + +- (void)lookupDeveloperIdentity:(AWSCognitoIdentityLookupDeveloperIdentityInput *)request + completionHandler:(void (^)(AWSCognitoIdentityLookupDeveloperIdentityResponse *response, NSError *error))completionHandler { + [[self lookupDeveloperIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityLookupDeveloperIdentityResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)mergeDeveloperIdentities:(AWSCognitoIdentityMergeDeveloperIdentitiesInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"MergeDeveloperIdentities" + outputClass:[AWSCognitoIdentityMergeDeveloperIdentitiesResponse class]]; +} + +- (void)mergeDeveloperIdentities:(AWSCognitoIdentityMergeDeveloperIdentitiesInput *)request + completionHandler:(void (^)(AWSCognitoIdentityMergeDeveloperIdentitiesResponse *response, NSError *error))completionHandler { + [[self mergeDeveloperIdentities:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityMergeDeveloperIdentitiesResponse *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +- (AWSTask *)setIdentityPoolRoles:(AWSCognitoIdentitySetIdentityPoolRolesInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"SetIdentityPoolRoles" + outputClass:nil]; +} + +- (void)setIdentityPoolRoles:(AWSCognitoIdentitySetIdentityPoolRolesInput *)request + completionHandler:(void (^)(NSError *error))completionHandler { + [[self setIdentityPoolRoles:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSError *error = task.error; + + if (completionHandler) { + completionHandler(error); + } + + return nil; + }]; +} + +- (AWSTask *)unlinkDeveloperIdentity:(AWSCognitoIdentityUnlinkDeveloperIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"UnlinkDeveloperIdentity" + outputClass:nil]; +} + +- (void)unlinkDeveloperIdentity:(AWSCognitoIdentityUnlinkDeveloperIdentityInput *)request + completionHandler:(void (^)(NSError *error))completionHandler { + [[self unlinkDeveloperIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSError *error = task.error; + + if (completionHandler) { + completionHandler(error); + } + + return nil; + }]; +} + +- (AWSTask *)unlinkIdentity:(AWSCognitoIdentityUnlinkIdentityInput *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"UnlinkIdentity" + outputClass:nil]; +} + +- (void)unlinkIdentity:(AWSCognitoIdentityUnlinkIdentityInput *)request + completionHandler:(void (^)(NSError *error))completionHandler { + [[self unlinkIdentity:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + NSError *error = task.error; + + if (completionHandler) { + completionHandler(error); + } + + return nil; + }]; +} + +- (AWSTask *)updateIdentityPool:(AWSCognitoIdentityIdentityPool *)request { + return [self invokeRequest:request + HTTPMethod:AWSHTTPMethodPOST + URLString:@"" + targetPrefix:@"AWSCognitoIdentityService" + operationName:@"UpdateIdentityPool" + outputClass:[AWSCognitoIdentityIdentityPool class]]; +} + +- (void)updateIdentityPool:(AWSCognitoIdentityIdentityPool *)request + completionHandler:(void (^)(AWSCognitoIdentityIdentityPool *response, NSError *error))completionHandler { + [[self updateIdentityPool:request] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { + AWSCognitoIdentityIdentityPool *result = task.result; + NSError *error = task.error; + + if (completionHandler) { + completionHandler(result, error); + } + + return nil; + }]; +} + +#pragma mark - + +@end diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDB.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDB.h new file mode 100644 index 00000000..e6b8b20c --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDB.h @@ -0,0 +1,5 @@ +#import "AWSFMDatabase.h" +#import "AWSFMResultSet.h" +#import "AWSFMDatabaseAdditions.h" +#import "AWSFMDatabaseQueue.h" +#import "AWSFMDatabasePool.h" diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase+Private.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase+Private.h new file mode 100644 index 00000000..d667426c --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase+Private.h @@ -0,0 +1,39 @@ +// +// FMDatabase+Private.h +// deleteme2 +// +// Created by Robert Ryan on 8/2/15. +// Copyright (c) 2015 Robert Ryan. All rights reserved. +// + +#ifndef deleteme2_FMDatabase_Private_h +#define deleteme2_FMDatabase_Private_h + +#import + +@class AWSFMDatabase; +@class AWSFMStatement; + +@interface AWSFMDatabase (Private) + +/** SQLite sqlite3 + + @see [`sqlite3`](http://www.sqlite.org/c3ref/sqlite3.html) + */ + +@property (nonatomic, assign, readonly) sqlite3 *db; + +@end + +@interface AWSFMStatement (Private) + +/** SQLite sqlite3_stmt + + @see [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@property (nonatomic, assign) sqlite3_stmt *statement; + +@end + +#endif diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.h new file mode 100644 index 00000000..23255353 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.h @@ -0,0 +1,1080 @@ +#import +#import "AWSFMResultSet.h" +#import "AWSFMDatabasePool.h" + + +#if ! __has_feature(objc_arc) + #define AWSFMDBAutorelease(__v) ([__v autorelease]); + #define AWSFMDBReturnAutoreleased AWSFMDBAutorelease + + #define AWSFMDBRetain(__v) ([__v retain]); + #define AWSFMDBReturnRetained AWSFMDBRetain + + #define AWSFMDBRelease(__v) ([__v release]); + + #define AWSFMDBDispatchQueueRelease(__v) (dispatch_release(__v)); +#else + // -fobjc-arc + #define AWSFMDBAutorelease(__v) + #define AWSFMDBReturnAutoreleased(__v) (__v) + + #define AWSFMDBRetain(__v) + #define AWSFMDBReturnRetained(__v) (__v) + + #define AWSFMDBRelease(__v) + +// If OS_OBJECT_USE_OBJC=1, then the dispatch objects will be treated like ObjC objects +// and will participate in ARC. +// See the section on "Dispatch Queues and Automatic Reference Counting" in "Grand Central Dispatch (GCD) Reference" for details. + #if OS_OBJECT_USE_OBJC + #define AWSFMDBDispatchQueueRelease(__v) + #else + #define AWSFMDBDispatchQueueRelease(__v) (dispatch_release(__v)); + #endif +#endif + +#if !__has_feature(objc_instancetype) + #define instancetype id +#endif + + +typedef int(^AWSFMDBExecuteStatementsCallbackBlock)(NSDictionary *resultsDictionary); + + +/** A SQLite ([http://sqlite.org/](http://sqlite.org/)) Objective-C wrapper. + + ### Usage + The three main classes in AWSFMDB are: + + - `FMDatabase` - Represents a single SQLite database. Used for executing SQL statements. + - `` - Represents the results of executing a query on an `FMDatabase`. + - `` - If you want to perform queries and updates on multiple threads, you'll want to use this class. + + ### See also + + - `` - A pool of `FMDatabase` objects. + - `` - A wrapper for `sqlite_stmt`. + + ### External links + + - [AWSFMDB on GitHub](https://github.com/ccgus/fmdb) including introductory documentation + - [SQLite web site](http://sqlite.org/) + - [AWSFMDB mailing list](http://groups.google.com/group/fmdb) + - [SQLite FAQ](http://www.sqlite.org/faq.html) + + @warning Do not instantiate a single `FMDatabase` object and use it across multiple threads. Instead, use ``. + + */ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-interface-ivars" + + +@interface AWSFMDatabase : NSObject { + + NSString* _databasePath; + BOOL _logsErrors; + BOOL _crashOnErrors; + BOOL _traceExecution; + BOOL _checkedOut; + BOOL _shouldCacheStatements; + BOOL _isExecutingStatement; + BOOL _inTransaction; + NSTimeInterval _maxBusyRetryTimeInterval; + NSTimeInterval _startBusyRetryTime; + + NSMutableDictionary *_cachedStatements; + NSMutableSet *_openResultSets; + NSMutableSet *_openFunctions; + + NSDateFormatter *_dateFormat; +} + +///----------------- +/// @name Properties +///----------------- + +/** Whether should trace execution */ + +@property (atomic, assign) BOOL traceExecution; + +/** Whether checked out or not */ + +@property (atomic, assign) BOOL checkedOut; + +/** Crash on errors */ + +@property (atomic, assign) BOOL crashOnErrors; + +/** Logs errors */ + +@property (atomic, assign) BOOL logsErrors; + +/** Dictionary of cached statements */ + +@property (atomic, retain) NSMutableDictionary *cachedStatements; + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + ++ (instancetype)databaseWithPath:(NSString*)inPath; + +/** Initialize a `FMDatabase` object. + + An `FMDatabase` is created with a path to a SQLite database file. This path can be one of these three: + + 1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you. + 2. An empty string (`@""`). An empty database is created at a temporary location. This database is deleted with the `FMDatabase` connection is closed. + 3. `nil`. An in-memory database is created. This database will be destroyed with the `FMDatabase` connection is closed. + + For example, to create/open a database in your Mac OS X `tmp` folder: + + FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"]; + + Or, in iOS, you might open a database in the app's `Documents` directory: + + NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; + NSString *dbPath = [docsPath stringByAppendingPathComponent:@"test.db"]; + FMDatabase *db = [FMDatabase databaseWithPath:dbPath]; + + (For more information on temporary and in-memory databases, read the sqlite documentation on the subject: [http://www.sqlite.org/inmemorydb.html](http://www.sqlite.org/inmemorydb.html)) + + @param inPath Path of database file + + @return `FMDatabase` object if successful; `nil` if failure. + + */ + +- (instancetype)initWithPath:(NSString*)inPath; + + +///----------------------------------- +/// @name Opening and closing database +///----------------------------------- + +/** Opening a new database connection + + The database is opened for reading and writing, and is created if it does not already exist. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open()](http://sqlite.org/c3ref/open.html) + @see openWithFlags: + @see close + */ + +- (BOOL)open; + +/** Opening a new database connection with flags and an optional virtual file system (VFS) + + @param flags one of the following three values, optionally combined with the `SQLITE_OPEN_NOMUTEX`, `SQLITE_OPEN_FULLMUTEX`, `SQLITE_OPEN_SHAREDCACHE`, `SQLITE_OPEN_PRIVATECACHE`, and/or `SQLITE_OPEN_URI` flags: + + `SQLITE_OPEN_READONLY` + + The database is opened in read-only mode. If the database does not already exist, an error is returned. + + `SQLITE_OPEN_READWRITE` + + The database is opened for reading and writing if possible, or reading only if the file is write protected by the operating system. In either case the database must already exist, otherwise an error is returned. + + `SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE` + + The database is opened for reading and writing, and is created if it does not already exist. This is the behavior that is always used for `open` method. + + If vfs is given the value is passed to the vfs parameter of sqlite3_open_v2. + + @return `YES` if successful, `NO` on error. + + @see [sqlite3_open_v2()](http://sqlite.org/c3ref/open.html) + @see open + @see close + + @warning Requires SQLite 3.5 + */ + +- (BOOL)openWithFlags:(int)flags; +- (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName; + +/** Closing a database connection + + @return `YES` if success, `NO` on error. + + @see [sqlite3_close()](http://sqlite.org/c3ref/close.html) + @see open + @see openWithFlags: + */ + +- (BOOL)close; + +/** Test to see if we have a good connection to the database. + + This will confirm whether: + + - is database open + - if open, it will try a simple SELECT statement and confirm that it succeeds. + + @return `YES` if everything succeeds, `NO` on failure. + */ + +- (BOOL)goodConnection; + + +///---------------------- +/// @name Perform updates +///---------------------- + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param outErr A reference to the `NSError` pointer to be updated with an auto released `NSError` object if an error if an error occurs. If `nil`, no `NSError` object will be returned. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + */ + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ...; + +/** Execute single update statement + + @see executeUpdate:withErrorAndBindings: + + @warning **Deprecated**: Please use `` instead. + */ + +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... __attribute__ ((deprecated)); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html), [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) to bind values to `?` placeholders in the SQL with the optional list of parameters, and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + + @note This technique supports the use of `?` placeholders in the SQL, automatically binding any supplied value parameters to those placeholders. This approach is more robust than techniques that entail using `stringWithFormat` to manually build SQL statements, which can be problematic if the values happened to include any characters that needed to be quoted. + + @note If you want to use this from Swift, please note that you must include `FMDatabaseVariadic.swift` in your project. Without that, you cannot use this method directly, and instead have to use methods such as ``. + */ + +- (BOOL)executeUpdate:(NSString*)sql, ...; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. Do not use `?` placeholders in the SQL if you use this method. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeUpdate: + @see lastError + @see lastErrorCode + @see lastErrorMessage + + @note This method does not technically perform a traditional printf-style replacement. What this method actually does is replace the printf-style percent sequences with a SQLite `?` placeholder, and then bind values to that placeholder. Thus the following command + + [db executeUpdateWithFormat:@"INSERT INTO test (name) VALUES (%@)", @"Gus"]; + + is actually replacing the `%@` with `?` placeholder, and then performing something equivalent to `` + + [db executeUpdate:@"INSERT INTO test (name) VALUES (?)", @"Gus"]; + + There are two reasons why this distinction is important. First, the printf-style escape sequences can only be used where it is permissible to use a SQLite `?` placeholder. You can use it only for values in SQL statements, but not for table names or column names or any other non-value context. This method also cannot be used in conjunction with `pragma` statements and the like. Second, note the lack of quotation marks in the SQL. The `VALUES` clause was _not_ `VALUES ('%@')` (like you might have to do if you built a SQL statement using `NSString` method `stringWithFormat`), but rather simply `VALUES (%@)`. + */ + +- (BOOL)executeUpdateWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) binding any `?` placeholders in the SQL with the optional list of parameters. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage +*/ + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments; + + +/** Execute single update statement + + This method executes a single SQL update statement (i.e. any SQL that does not return results, such as `UPDATE`, `INSERT`, or `DELETE`. This method employs [`sqlite3_prepare_v2`](http://sqlite.org/c3ref/prepare.html) and [`sqlite_step`](http://sqlite.org/c3ref/step.html) to perform the update. Unlike the other `executeUpdate` methods, this uses printf-style formatters (e.g. `%s`, `%d`, etc.) to build the SQL. + + The optional values provided to this method should be objects (e.g. `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects), not fundamental data types (e.g. `int`, `long`, `NSInteger`, etc.). This method automatically handles the aforementioned object types, and all other object types will be interpreted as text values using the object's `description` method. + + @param sql The SQL to be performed, with optional `?` placeholders. + + @param args A `va_list` of arguments. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + */ + +- (BOOL)executeUpdate:(NSString*)sql withVAList: (va_list)args; + +/** Execute multiple SQL statements + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeStatements:withResultBlock: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql; + +/** Execute multiple SQL statements with callback handler + + This executes a series of SQL statements that are combined in a single string (e.g. the SQL generated by the `sqlite3` command line `.dump` command). This accepts no value parameters, but rather simply expects a single string with multiple SQL statements, each terminated with a semicolon. This uses `sqlite3_exec`. + + @param sql The SQL to be performed. + @param block A block that will be called for any result sets returned by any SQL statements. + Note, if you supply this block, it must return integer value, zero upon success (this would be a good opportunity to use SQLITE_OK), + non-zero value upon failure (which will stop the bulk execution of the SQL). If a statement returns values, the block will be called with the results from the query in NSDictionary *resultsDictionary. + This may be `nil` if you don't care to receive any results. + + @return `YES` upon success; `NO` upon failure. If failed, you can call ``, + ``, or `` for diagnostic information regarding the failure. + + @see executeStatements: + @see [sqlite3_exec()](http://sqlite.org/c3ref/exec.html) + + */ + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(AWSFMDBExecuteStatementsCallbackBlock)block; + +/** Last insert rowid + + Each entry in an SQLite table has a unique 64-bit signed integer key called the "rowid". The rowid is always available as an undeclared column named `ROWID`, `OID`, or `_ROWID_` as long as those names are not also used by explicitly declared columns. If the table has a column of type `INTEGER PRIMARY KEY` then that column is another alias for the rowid. + + This routine returns the rowid of the most recent successful `INSERT` into the database from the database connection in the first argument. As of SQLite version 3.7.7, this routines records the last insert rowid of both ordinary tables and virtual tables. If no successful `INSERT`s have ever occurred on that database connection, zero is returned. + + @return The rowid of the last inserted row. + + @see [sqlite3_last_insert_rowid()](http://sqlite.org/c3ref/last_insert_rowid.html) + + */ + +- (long long int)lastInsertRowId; + +/** The number of rows changed by prior SQL statement. + + This function returns the number of database rows that were changed or inserted or deleted by the most recently completed SQL statement on the database connection specified by the first parameter. Only changes that are directly specified by the INSERT, UPDATE, or DELETE statement are counted. + + @return The number of rows changed by prior SQL statement. + + @see [sqlite3_changes()](http://sqlite.org/c3ref/changes.html) + + */ + +- (int)changes; + + +///------------------------- +/// @name Retrieving results +///------------------------- + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + This method employs [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) for any optional value parameters. This properly escapes any characters that need escape sequences (e.g. quotation marks), which eliminates simple SQL errors as well as protects against SQL injection attacks. This method natively handles `NSString`, `NSNumber`, `NSNull`, `NSDate`, and `NSData` objects. All other object types will be interpreted as text values using the object's `description` method. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param ... Optional parameters to bind to `?` placeholders in the SQL statement. These should be Objective-C objects (e.g. `NSString`, `NSNumber`, etc.), not fundamental C data types (e.g. `int`, `char *`, etc.). + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + @see [`sqlite3_bind`](http://sqlite.org/c3ref/bind_blob.html) + + @note If you want to use this from Swift, please note that you must include `FMDatabaseVariadic.swift` in your project. Without that, you cannot use this method directly, and instead have to use methods such as ``. + */ + +- (AWSFMResultSet *)executeQuery:(NSString*)sql, ...; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param format The SQL to be performed, with `printf`-style escape sequences. + + @param ... Optional parameters to bind to use in conjunction with the `printf`-style escape sequences in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see executeQuery: + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + + @note This method does not technically perform a traditional printf-style replacement. What this method actually does is replace the printf-style percent sequences with a SQLite `?` placeholder, and then bind values to that placeholder. Thus the following command + + [db executeQueryWithFormat:@"SELECT * FROM test WHERE name=%@", @"Gus"]; + + is actually replacing the `%@` with `?` placeholder, and then performing something equivalent to `` + + [db executeQuery:@"SELECT * FROM test WHERE name=?", @"Gus"]; + + There are two reasons why this distinction is important. First, the printf-style escape sequences can only be used where it is permissible to use a SQLite `?` placeholder. You can use it only for values in SQL statements, but not for table names or column names or any other non-value context. This method also cannot be used in conjunction with `pragma` statements and the like. Second, note the lack of quotation marks in the SQL. The `WHERE` clause was _not_ `WHERE name='%@'` (like you might have to do if you built a SQL statement using `NSString` method `stringWithFormat`), but rather simply `WHERE name=%@`. + + */ + +- (AWSFMResultSet *)executeQueryWithFormat:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSArray` of objects to be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments; + +/** Execute select statement + + Executing queries returns an `` object if successful, and `nil` upon failure. Like executing updates, there is a variant that accepts an `NSError **` parameter. Otherwise you should use the `` and `` methods to determine why a query failed. + + In order to iterate through the results of your query, you use a `while()` loop. You also need to "step" (via `<[FMResultSet next]>`) from one record to the other. + + @param sql The SELECT statement to be performed, with optional `?` placeholders. + + @param arguments A `NSDictionary` of objects keyed by column names that will be used when binding values to the `?` placeholders in the SQL statement. + + @return A `` for the result set upon success; `nil` upon failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see FMResultSet + @see [`FMResultSet next`](<[FMResultSet next]>) + */ + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments; + + +// Documentation forthcoming. +- (AWSFMResultSet *)executeQuery:(NSString*)sql withVAList: (va_list)args; + +///------------------- +/// @name Transactions +///------------------- + +/** Begin a transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginDeferredTransaction + @see inTransaction + */ + +- (BOOL)beginTransaction; + +/** Begin a deferred transaction + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see commit + @see rollback + @see beginTransaction + @see inTransaction + */ + +- (BOOL)beginDeferredTransaction; + +/** Commit a transaction + + Commit a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see rollback + @see inTransaction + */ + +- (BOOL)commit; + +/** Rollback a transaction + + Rollback a transaction that was initiated with either `` or with ``. + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see inTransaction + */ + +- (BOOL)rollback; + +/** Identify whether currently in a transaction or not + + @return `YES` if currently within transaction; `NO` if not. + + @see beginTransaction + @see beginDeferredTransaction + @see commit + @see rollback + */ + +- (BOOL)inTransaction; + + +///---------------------------------------- +/// @name Cached statements and result sets +///---------------------------------------- + +/** Clear cached statements */ + +- (void)clearCachedStatements; + +/** Close all open result sets */ + +- (void)closeOpenResultSets; + +/** Whether database has any open result sets + + @return `YES` if there are open result sets; `NO` if not. + */ + +- (BOOL)hasOpenResultSets; + +/** Return whether should cache statements or not + + @return `YES` if should cache statements; `NO` if not. + */ + +- (BOOL)shouldCacheStatements; + +/** Set whether should cache statements or not + + @param value `YES` if should cache statements; `NO` if not. + */ + +- (void)setShouldCacheStatements:(BOOL)value; + + +///------------------------- +/// @name Encryption methods +///------------------------- + +/** Set encryption key. + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKey:(NSString*)key; + +/** Reset encryption key + + @param key The key to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekey:(NSString*)key; + +/** Set encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)setKeyWithData:(NSData *)keyData; + +/** Reset encryption key using `keyData`. + + @param keyData The `NSData` to be used. + + @return `YES` if success, `NO` on error. + + @see http://www.sqlite-encrypt.com/develop-guide.htm + + @warning You need to have purchased the sqlite encryption extensions for this method to work. + */ + +- (BOOL)rekeyWithData:(NSData *)keyData; + + +///------------------------------ +/// @name General inquiry methods +///------------------------------ + +/** The path of the database file + + @return path of database. + + */ + +- (NSString *)databasePath; + +/** The underlying SQLite handle + + @return The `sqlite3` pointer. + + */ + +- (void*)sqliteHandle; + + +///----------------------------- +/// @name Retrieving error codes +///----------------------------- + +/** Last error message + + Returns the English-language text that describes the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return `NSString` of the last error message. + + @see [sqlite3_errmsg()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorCode + @see lastError + + */ + +- (NSString*)lastErrorMessage; + +/** Last error code + + Returns the numeric result code or extended result code for the most recent failed SQLite API call associated with a database connection. If a prior API call failed but the most recent API call succeeded, this return value is undefined. + + @return Integer value of the last error code. + + @see [sqlite3_errcode()](http://sqlite.org/c3ref/errcode.html) + @see lastErrorMessage + @see lastError + + */ + +- (int)lastErrorCode; + +/** Had error + + @return `YES` if there was an error, `NO` if no error. + + @see lastError + @see lastErrorCode + @see lastErrorMessage + + */ + +- (BOOL)hadError; + +/** Last error + + @return `NSError` representing the last error. + + @see lastErrorCode + @see lastErrorMessage + + */ + +- (NSError*)lastError; + + +// description forthcoming +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeoutInSeconds; +- (NSTimeInterval)maxBusyRetryTimeInterval; + + +///------------------ +/// @name Save points +///------------------ + +/** Start save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + */ + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Release save point + + @param name Name of save point. + + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Roll back to save point + + @param name Name of save point. + @param outErr A `NSError` object to receive any error object (if any). + + @return `YES` on success; `NO` on failure. If failed, you can call ``, ``, or `` for diagnostic information regarding the failure. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + + */ + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr; + +/** Start save point + + @param block Block of code to perform from within save point. + + @return The NSError corresponding to the error, if any. If no error, returns `nil`. + + @see startSavePointWithName:error: + @see releaseSavePointWithName:error: + @see rollbackToSavePointWithName:error: + + */ + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block; + + +///---------------------------- +/// @name SQLite library status +///---------------------------- + +/** Test to see if the library is threadsafe + + @return `NO` if and only if SQLite was compiled with mutexing code omitted due to the SQLITE_THREADSAFE compile-time option being set to 0. + + @see [sqlite3_threadsafe()](http://sqlite.org/c3ref/threadsafe.html) + */ + ++ (BOOL)isSQLiteThreadSafe; + +/** Run-time library version numbers + + @return The sqlite library version string. + + @see [sqlite3_libversion()](http://sqlite.org/c3ref/libversion.html) + */ + ++ (NSString*)sqliteLibVersion; + + ++ (NSString*)AWSFMDBUserVersion; + ++ (SInt32)AWSFMDBVersion; + + +///------------------------ +/// @name Make SQL function +///------------------------ + +/** Adds SQL functions or aggregates or to redefine the behavior of existing SQL functions or aggregates. + + For example: + + [queue inDatabase:^(FMDatabase *adb) { + + [adb executeUpdate:@"create table ftest (foo text)"]; + [adb executeUpdate:@"insert into ftest values ('hello')"]; + [adb executeUpdate:@"insert into ftest values ('hi')"]; + [adb executeUpdate:@"insert into ftest values ('not h!')"]; + [adb executeUpdate:@"insert into ftest values ('definitely not h!')"]; + + [adb makeFunctionNamed:@"StringStartsWithH" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) { + if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) { + @autoreleasepool { + const char *c = (const char *)sqlite3_value_text(aargv[0]); + NSString *s = [NSString stringWithUTF8String:c]; + sqlite3_result_int(context, [s hasPrefix:@"h"]); + } + } + else { + NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__); + sqlite3_result_null(context); + } + }]; + + int rowCount = 0; + FMResultSet *ars = [adb executeQuery:@"select * from ftest where StringStartsWithH(foo)"]; + while ([ars next]) { + rowCount++; + NSLog(@"Does %@ start with 'h'?", [rs stringForColumnIndex:0]); + } + AWSFMDBQuickCheck(rowCount == 2); + }]; + + @param name Name of function + + @param count Maximum number of parameters + + @param block The block of code for the function + + @see [sqlite3_create_function()](http://sqlite.org/c3ref/create_function.html) + */ + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(void *context, int argc, void **argv))block; + + +///--------------------- +/// @name Date formatter +///--------------------- + +/** Generate an `NSDateFormatter` that won't be broken by permutations of timezones or locales. + + Use this method to generate values to set the dateFormat property. + + Example: + + myDB.dateFormat = [FMDatabase storeableDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + + @param format A valid NSDateFormatter format string. + + @return A `NSDateFormatter` that can be used for converting dates to strings and vice versa. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note that `NSDateFormatter` is not thread-safe, so the formatter generated by this method should be assigned to only one AWSFMDB instance and should not be used for other purposes. + + */ + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format; + +/** Test whether the database has a date formatter assigned. + + @return `YES` if there is a date formatter; `NO` if not. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (BOOL)hasDateFormatter; + +/** Set to a date formatter to use string dates with sqlite instead of the default UNIX timestamps. + + @param format Set to nil to use UNIX timestamps. Defaults to nil. Should be set using a formatter generated using FMDatabase::storeableDateFormat. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + + @warning Note there is no direct getter for the `NSDateFormatter`, and you should not use the formatter you pass to AWSFMDB for other purposes, as `NSDateFormatter` is not thread-safe. + */ + +- (void)setDateFormat:(NSDateFormatter *)format; + +/** Convert the supplied NSString to NSDate, using the current database formatter. + + @param s `NSString` to convert to `NSDate`. + + @return The `NSDate` object; or `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSDate *)dateFromString:(NSString *)s; + +/** Convert the supplied NSDate to NSString, using the current database formatter. + + @param date `NSDate` of date to convert to `NSString`. + + @return The `NSString` representation of the date; `nil` if no formatter is set. + + @see hasDateFormatter + @see setDateFormat: + @see dateFromString: + @see stringFromDate: + @see storeableDateFormat: + */ + +- (NSString *)stringFromDate:(NSDate *)date; + +@end + + +/** Objective-C wrapper for `sqlite3_stmt` + + This is a wrapper for a SQLite `sqlite3_stmt`. Generally when using AWSFMDB you will not need to interact directly with `FMStatement`, but rather with `` and `` only. + + ### See also + + - `` + - `` + - [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@interface AWSFMStatement : NSObject { + NSString *_query; + long _useCount; + BOOL _inUse; +} + +///----------------- +/// @name Properties +///----------------- + +/** Usage count */ + +@property (atomic, assign) long useCount; + +/** SQL statement */ + +@property (atomic, retain) NSString *query; + +/** SQLite sqlite3_stmt + + @see [`sqlite3_stmt`](http://www.sqlite.org/c3ref/stmt.html) + */ + +@property (atomic, assign) void *statement; + +/** Indication of whether the statement is in use */ + +@property (atomic, assign) BOOL inUse; + +///---------------------------- +/// @name Closing and Resetting +///---------------------------- + +/** Close statement */ + +- (void)close; + +/** Reset statement */ + +- (void)reset; + +@end + +#pragma clang diagnostic pop + diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.m b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.m new file mode 100644 index 00000000..1b376431 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabase.m @@ -0,0 +1,1438 @@ +#import "AWSFMDatabase.h" +#import "unistd.h" +#import +#import "AWSFMDatabase+Private.h" + +@interface AWSFMDatabase () + +@property (nonatomic, assign) sqlite3 *db; + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; + +@end + +@implementation AWSFMDatabase +@synthesize cachedStatements=_cachedStatements; +@synthesize logsErrors=_logsErrors; +@synthesize crashOnErrors=_crashOnErrors; +@synthesize checkedOut=_checkedOut; +@synthesize traceExecution=_traceExecution; + +#pragma mark FMDatabase instantiation and deallocation + ++ (instancetype)databaseWithPath:(NSString*)aPath { + return AWSFMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + assert(sqlite3_threadsafe()); // whoa there big boy- gotta make sure sqlite it happy with what we're going to do. + + self = [super init]; + + if (self) { + _databasePath = [aPath copy]; + _openResultSets = [[NSMutableSet alloc] init]; + _db = nil; + _logsErrors = YES; + _crashOnErrors = NO; + _maxBusyRetryTimeInterval = 2; + } + + return self; +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + AWSFMDBRelease(_openResultSets); + AWSFMDBRelease(_cachedStatements); + AWSFMDBRelease(_dateFormat); + AWSFMDBRelease(_databasePath); + AWSFMDBRelease(_openFunctions); + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (NSString *)databasePath { + return _databasePath; +} + ++ (NSString*)AWSFMDBUserVersion { + return @"2.5"; +} + +// returns 0x0240 for version 2.4. This makes it super easy to do things like: +// /* need to make sure to do X with AWSFMDB version 2.4 or later */ +// if ([FMDatabase AWSFMDBVersion] >= 0x0240) { … } + ++ (SInt32)AWSFMDBVersion { + + // we go through these hoops so that we only have to change the version number in a single spot. + static dispatch_once_t once; + static SInt32 AWSFMDBVersionVal = 0; + + dispatch_once(&once, ^{ + NSString *prodVersion = [self AWSFMDBUserVersion]; + + if ([[prodVersion componentsSeparatedByString:@"."] count] < 3) { + prodVersion = [prodVersion stringByAppendingString:@".0"]; + } + + NSString *junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; + + char *e = nil; + AWSFMDBVersionVal = (int) strtoul([junk UTF8String], &e, 16); + + }); + + + return AWSFMDBVersionVal; +} + +#pragma mark SQLite information + ++ (NSString*)sqliteLibVersion { + return [NSString stringWithFormat:@"%s", sqlite3_libversion()]; +} + ++ (BOOL)isSQLiteThreadSafe { + // make sure to read the sqlite headers on this guy! + return sqlite3_threadsafe() != 0; +} + +- (void*)sqliteHandle { + return _db; +} + +- (const char*)sqlitePath { + + if (!_databasePath) { + return ":memory:"; + } + + if ([_databasePath length] == 0) { + return ""; // this creates a temporary database (it's an sqlite thing). + } + + return [_databasePath fileSystemRepresentation]; + +} + +#pragma mark Open and close database + +- (BOOL)open { + if (_db) { + return YES; + } + + int err = sqlite3_open([self sqlitePath], &_db ); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + + return YES; +} + +- (BOOL)openWithFlags:(int)flags { + return [self openWithFlags:flags vfs:nil]; +} +- (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName; { +#if SQLITE_VERSION_NUMBER >= 3005000 + if (_db) { + return YES; + } + + int err = sqlite3_open_v2([self sqlitePath], &_db, flags, [vfsName UTF8String]); + if(err != SQLITE_OK) { + NSLog(@"error opening!: %d", err); + return NO; + } + + if (_maxBusyRetryTimeInterval > 0.0) { + // set the handler + [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; + } + + return YES; +#else + NSLog(@"Requires SQLite 3.5; will just open"); + return [self open]; +#endif + +} + + +- (BOOL)close { + + [self clearCachedStatements]; + [self closeOpenResultSets]; + + if (!_db) { + return YES; + } + + int rc; + BOOL retry; + BOOL triedFinalizingOpenStatements = NO; + + do { + retry = NO; + rc = sqlite3_close(_db); + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + if (!triedFinalizingOpenStatements) { + triedFinalizingOpenStatements = YES; + sqlite3_stmt *pStmt; + while ((pStmt = sqlite3_next_stmt(_db, nil)) !=0) { + NSLog(@"Closing leaked statement"); + sqlite3_finalize(pStmt); + retry = YES; + } + } + } + else if (SQLITE_OK != rc) { + NSLog(@"error closing!: %d", rc); + } + } + while (retry); + + _db = nil; + return YES; +} + +#pragma mark Busy handler routines + +// NOTE: appledoc seems to choke on this function for some reason; +// so when generating documentation, you might want to ignore the +// .m files so that it only documents the public interfaces outlined +// in the .h files. +// +// This is a known appledoc bug that it has problems with C functions +// within a class implementation, but for some reason, only this +// C function causes problems; the rest don't. Anyway, ignoring the .m +// files with appledoc will prevent this problem from occurring. + +static int AWSFMDBDatabaseBusyHandler(void *f, int count) { + AWSFMDatabase *self = (__bridge AWSFMDatabase*)f; + + if (count == 0) { + self->_startBusyRetryTime = [NSDate timeIntervalSinceReferenceDate]; + return 1; + } + + NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - (self->_startBusyRetryTime); + + if (delta < [self maxBusyRetryTimeInterval]) { + int requestedSleepInMillseconds = (int) arc4random_uniform(50) + 50; + int actualSleepInMilliseconds = sqlite3_sleep(requestedSleepInMillseconds); + if (actualSleepInMilliseconds != requestedSleepInMillseconds) { + NSLog(@"WARNING: Requested sleep of %i milliseconds, but SQLite returned %i. Maybe SQLite wasn't built with HAVE_USLEEP=1?", requestedSleepInMillseconds, actualSleepInMilliseconds); + } + return 1; + } + + return 0; +} + +- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout { + + _maxBusyRetryTimeInterval = timeout; + + if (!_db) { + return; + } + + if (timeout > 0) { + sqlite3_busy_handler(_db, &AWSFMDBDatabaseBusyHandler, (__bridge void *)(self)); + } + else { + // turn it off otherwise + sqlite3_busy_handler(_db, nil, nil); + } +} + +- (NSTimeInterval)maxBusyRetryTimeInterval { + return _maxBusyRetryTimeInterval; +} + + +// we no longer make busyRetryTimeout public +// but for folks who don't bother noticing that the interface to FMDatabase changed, +// we'll still implement the method so they don't get suprise crashes +- (int)busyRetryTimeout { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"AWSFMDB: busyRetryTimeout no longer works, please use maxBusyRetryTimeInterval"); + return -1; +} + +- (void)setBusyRetryTimeout:(int)i { + NSLog(@"%s:%d", __FUNCTION__, __LINE__); + NSLog(@"AWSFMDB: setBusyRetryTimeout does nothing, please use setMaxBusyRetryTimeInterval:"); +} + +#pragma mark Result set functions + +- (BOOL)hasOpenResultSets { + return [_openResultSets count] > 0; +} + +- (void)closeOpenResultSets { + + //Copy the set so we don't get mutation errors + NSSet *openSetCopy = AWSFMDBReturnAutoreleased([_openResultSets copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + AWSFMResultSet *rs = (AWSFMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + + [rs setParentDB:nil]; + [rs close]; + + [_openResultSets removeObject:rsInWrappedInATastyValueMeal]; + } +} + +- (void)resultSetDidClose:(AWSFMResultSet *)resultSet { + NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet]; + + [_openResultSets removeObject:setValue]; +} + +#pragma mark Cached statements + +- (void)clearCachedStatements { + + for (NSMutableSet *statements in [_cachedStatements objectEnumerator]) { + [statements makeObjectsPerformSelector:@selector(close)]; + } + + [_cachedStatements removeAllObjects]; +} + +- (AWSFMStatement*)cachedStatementForQuery:(NSString*)query { + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + + return [[statements objectsPassingTest:^BOOL(AWSFMStatement* statement, BOOL *stop) { + + *stop = ![statement inUse]; + return *stop; + + }] anyObject]; +} + + +- (void)setCachedStatement:(AWSFMStatement*)statement forQuery:(NSString*)query { + + query = [query copy]; // in case we got handed in a mutable string... + [statement setQuery:query]; + + NSMutableSet* statements = [_cachedStatements objectForKey:query]; + if (!statements) { + statements = [NSMutableSet set]; + } + + [statements addObject:statement]; + + [_cachedStatements setObject:statements forKey:query]; + + AWSFMDBRelease(query); +} + +#pragma mark Key routines + +- (BOOL)rekey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self rekeyWithData:keyData]; +} + +- (BOOL)rekeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_rekey(_db, [keyData bytes], (int)[keyData length]); + + if (rc != SQLITE_OK) { + NSLog(@"error on rekey: %d", rc); + NSLog(@"%@", [self lastErrorMessage]); + } + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +- (BOOL)setKey:(NSString*)key { + NSData *keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + + return [self setKeyWithData:keyData]; +} + +- (BOOL)setKeyWithData:(NSData *)keyData { +#ifdef SQLITE_HAS_CODEC + if (!keyData) { + return NO; + } + + int rc = sqlite3_key(_db, [keyData bytes], (int)[keyData length]); + + return (rc == SQLITE_OK); +#else + return NO; +#endif +} + +#pragma mark Date routines + ++ (NSDateFormatter *)storeableDateFormat:(NSString *)format { + + NSDateFormatter *result = AWSFMDBReturnAutoreleased([[NSDateFormatter alloc] init]); + result.dateFormat = format; + result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + result.locale = AWSFMDBReturnAutoreleased([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); + return result; +} + + +- (BOOL)hasDateFormatter { + return _dateFormat != nil; +} + +- (void)setDateFormat:(NSDateFormatter *)format { + AWSFMDBAutorelease(_dateFormat); + _dateFormat = AWSFMDBReturnRetained(format); +} + +- (NSDate *)dateFromString:(NSString *)s { + return [_dateFormat dateFromString:s]; +} + +- (NSString *)stringFromDate:(NSDate *)date { + return [_dateFormat stringFromDate:date]; +} + +#pragma mark State of database + +- (BOOL)goodConnection { + + if (!_db) { + return NO; + } + + AWSFMResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"]; + + if (rs) { + [rs close]; + return YES; + } + + return NO; +} + +- (void)warnInUse { + NSLog(@"The FMDatabase %@ is currently in use.", self); + +#ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is currently in use.", self); + abort(); + } +#endif +} + +- (BOOL)databaseExists { + + if (!_db) { + + NSLog(@"The FMDatabase %@ is not open.", self); + + #ifndef NS_BLOCK_ASSERTIONS + if (_crashOnErrors) { + NSAssert(false, @"The FMDatabase %@ is not open.", self); + abort(); + } + #endif + + return NO; + } + + return YES; +} + +#pragma mark Error routines + +- (NSString*)lastErrorMessage { + return [NSString stringWithUTF8String:sqlite3_errmsg(_db)]; +} + +- (BOOL)hadError { + int lastErrCode = [self lastErrorCode]; + + return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW); +} + +- (int)lastErrorCode { + return sqlite3_errcode(_db); +} + +- (NSError*)errorWithMessage:(NSString*)message { + NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; + + return [NSError errorWithDomain:@"AWSFMDatabase" code:sqlite3_errcode(_db) userInfo:errorMessage]; +} + +- (NSError*)lastError { + return [self errorWithMessage:[self lastErrorMessage]]; +} + +#pragma mark Update information routines + +- (sqlite_int64)lastInsertRowId { + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + sqlite_int64 ret = sqlite3_last_insert_rowid(_db); + + _isExecutingStatement = NO; + + return ret; +} + +- (int)changes { + if (_isExecutingStatement) { + [self warnInUse]; + return 0; + } + + _isExecutingStatement = YES; + + int ret = sqlite3_changes(_db); + + _isExecutingStatement = NO; + + return ret; +} + +#pragma mark SQL manipulation + +- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt { + + if ((!obj) || ((NSNull *)obj == [NSNull null])) { + sqlite3_bind_null(pStmt, idx); + } + + // FIXME - someday check the return codes on these binds. + else if ([obj isKindOfClass:[NSData class]]) { + const void *bytes = [obj bytes]; + if (!bytes) { + // it's an empty NSData object, aka [NSData data]. + // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob. + bytes = ""; + } + sqlite3_bind_blob(pStmt, idx, bytes, (int)[obj length], SQLITE_STATIC); + } + else if ([obj isKindOfClass:[NSDate class]]) { + if (self.hasDateFormatter) + sqlite3_bind_text(pStmt, idx, [[self stringFromDate:obj] UTF8String], -1, SQLITE_STATIC); + else + sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]); + } + else if ([obj isKindOfClass:[NSNumber class]]) { + + if (strcmp([obj objCType], @encode(char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj charValue]); + } + else if (strcmp([obj objCType], @encode(unsigned char)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedCharValue]); + } + else if (strcmp([obj objCType], @encode(short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj shortValue]); + } + else if (strcmp([obj objCType], @encode(unsigned short)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj unsignedShortValue]); + } + else if (strcmp([obj objCType], @encode(int)) == 0) { + sqlite3_bind_int(pStmt, idx, [obj intValue]); + } + else if (strcmp([obj objCType], @encode(unsigned int)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedIntValue]); + } + else if (strcmp([obj objCType], @encode(long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongValue]); + } + else if (strcmp([obj objCType], @encode(long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, [obj longLongValue]); + } + else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) { + sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongLongValue]); + } + else if (strcmp([obj objCType], @encode(float)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj floatValue]); + } + else if (strcmp([obj objCType], @encode(double)) == 0) { + sqlite3_bind_double(pStmt, idx, [obj doubleValue]); + } + else if (strcmp([obj objCType], @encode(BOOL)) == 0) { + sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0)); + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } + } + else { + sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); + } +} + +- (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments { + + NSUInteger length = [sql length]; + unichar last = '\0'; + for (NSUInteger i = 0; i < length; ++i) { + id arg = nil; + unichar current = [sql characterAtIndex:i]; + unichar add = current; + if (last == '%') { + switch (current) { + case '@': + arg = va_arg(args, id); + break; + case 'c': + // warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSString stringWithFormat:@"%c", va_arg(args, int)]; + break; + case 's': + arg = [NSString stringWithUTF8String:va_arg(args, char*)]; + break; + case 'd': + case 'D': + case 'i': + arg = [NSNumber numberWithInt:va_arg(args, int)]; + break; + case 'u': + case 'U': + arg = [NSNumber numberWithUnsignedInt:va_arg(args, unsigned int)]; + break; + case 'h': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + // warning: second argument to 'va_arg' is of promotable type 'short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithShort:(short)(va_arg(args, int))]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + // warning: second argument to 'va_arg' is of promotable type 'unsigned short'; this va_arg has undefined behavior because arguments will be promoted to 'int' + arg = [NSNumber numberWithUnsignedShort:(unsigned short)(va_arg(args, uint))]; + } + else { + i--; + } + break; + case 'q': + i++; + if (i < length && [sql characterAtIndex:i] == 'i') { + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + break; + case 'f': + arg = [NSNumber numberWithDouble:va_arg(args, double)]; + break; + case 'g': + // warning: second argument to 'va_arg' is of promotable type 'float'; this va_arg has undefined behavior because arguments will be promoted to 'double' + arg = [NSNumber numberWithFloat:(float)(va_arg(args, double))]; + break; + case 'l': + i++; + if (i < length) { + unichar next = [sql characterAtIndex:i]; + if (next == 'l') { + i++; + if (i < length && [sql characterAtIndex:i] == 'd') { + //%lld + arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; + } + else if (i < length && [sql characterAtIndex:i] == 'u') { + //%llu + arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; + } + else { + i--; + } + } + else if (next == 'd') { + //%ld + arg = [NSNumber numberWithLong:va_arg(args, long)]; + } + else if (next == 'u') { + //%lu + arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)]; + } + else { + i--; + } + } + else { + i--; + } + break; + default: + // something else that we can't interpret. just pass it on through like normal + break; + } + } + else if (current == '%') { + // percent sign; skip this character + add = '\0'; + } + + if (arg != nil) { + [cleanedSQL appendString:@"?"]; + [arguments addObject:arg]; + } + else if (add == (unichar)'@' && last == (unichar) '%') { + [cleanedSQL appendFormat:@"NULL"]; + } + else if (add != '\0') { + [cleanedSQL appendFormat:@"%C", add]; + } + last = current; + } +} + +#pragma mark Execute queries + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return 0x00; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return 0x00; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + AWSFMStatement *statement = 0x00; + AWSFMResultSet *rs = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeQuery: %@", self, sql); + } + + if (_shouldCacheStatements) { + statement = [self cachedStatementForQuery:sql]; + pStmt = statement ? [statement statement] : 0x00; + [statement reset]; + } + + if (!pStmt) { + + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!) + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + if (_traceExecution) { + NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); + } + + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + AWSFMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + if (idx != queryCount) { + NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)"); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return nil; + } + + AWSFMDBRetain(statement); // to balance the release below + + if (!statement) { + statement = [[AWSFMStatement alloc] init]; + [statement setStatement:pStmt]; + + if (_shouldCacheStatements && sql) { + [self setCachedStatement:statement forQuery:sql]; + } + } + + // the statement gets closed in rs's dealloc or [rs close]; + rs = [AWSFMResultSet resultSetWithStatement:statement usingParentDatabase:self]; + [rs setQuery:sql]; + + NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs]; + [_openResultSets addObject:openResultSet]; + + [statement setUseCount:[statement useCount] + 1]; + + AWSFMDBRelease(statement); + + _isExecutingStatement = NO; + + return rs; +} + +- (AWSFMResultSet *)executeQuery:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (AWSFMResultSet *)executeQueryWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeQuery:sql withArgumentsInArray:arguments]; +} + +- (AWSFMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeQuery:sql withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (AWSFMResultSet *)executeQuery:(NSString*)sql withVAList:(va_list)args { + return [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +#pragma mark Execute updates + +- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + + if (![self databaseExists]) { + return NO; + } + + if (_isExecutingStatement) { + [self warnInUse]; + return NO; + } + + _isExecutingStatement = YES; + + int rc = 0x00; + sqlite3_stmt *pStmt = 0x00; + AWSFMStatement *cachedStmt = 0x00; + + if (_traceExecution && sql) { + NSLog(@"%@ executeUpdate: %@", self, sql); + } + + if (_shouldCacheStatements) { + cachedStmt = [self cachedStatementForQuery:sql]; + pStmt = cachedStmt ? [cachedStmt statement] : 0x00; + [cachedStmt reset]; + } + + if (!pStmt) { + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + + if (SQLITE_OK != rc) { + if (_logsErrors) { + NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + NSLog(@"DB Query: %@", sql); + NSLog(@"DB Path: %@", _databasePath); + } + + if (_crashOnErrors) { + NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); + abort(); + } + + sqlite3_finalize(pStmt); + + if (outErr) { + *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; + } + + _isExecutingStatement = NO; + return NO; + } + } + + id obj; + int idx = 0; + int queryCount = sqlite3_bind_parameter_count(pStmt); + + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support + if (dictionaryArgs) { + + for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { + + // Prefix the key with a colon. + NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + + if (_traceExecution) { + NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); + } + // Get the index for the parameter name. + int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); + + AWSFMDBRelease(parameterName); + + if (namedIdx > 0) { + // Standard binding from here. + [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; + + // increment the binding count, so our check below works out + idx++; + } + else { + NSLog(@"Could not find index for %@", dictionaryKey); + } + } + } + else { + + while (idx < queryCount) { + + if (arrayArgs && idx < (int)[arrayArgs count]) { + obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; + } + else if (args) { + obj = va_arg(args, id); + } + else { + //We ran out of arguments + break; + } + + if (_traceExecution) { + if ([obj isKindOfClass:[NSData class]]) { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); + } + else { + NSLog(@"obj: %@", obj); + } + } + + idx++; + + [self bindObject:obj toColumn:idx inStatement:pStmt]; + } + } + + + if (idx != queryCount) { + NSLog(@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql); + sqlite3_finalize(pStmt); + _isExecutingStatement = NO; + return NO; + } + + /* Call sqlite3_step() to run the virtual machine. Since the SQL being + ** executed is not a SELECT statement, we assume no data will be returned. + */ + + rc = sqlite3_step(pStmt); + + if (SQLITE_DONE == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + if (_logsErrors) { + NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + else { + // wtf? + if (_logsErrors) { + NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + if (rc == SQLITE_ROW) { + NSAssert(NO, @"A executeUpdate is being called with a query string '%@'", sql); + } + + if (_shouldCacheStatements && !cachedStmt) { + cachedStmt = [[AWSFMStatement alloc] init]; + + [cachedStmt setStatement:pStmt]; + + [self setCachedStatement:cachedStmt forQuery:sql]; + + AWSFMDBRelease(cachedStmt); + } + + int closeErrorCode; + + if (cachedStmt) { + [cachedStmt setUseCount:[cachedStmt useCount] + 1]; + closeErrorCode = sqlite3_reset(pStmt); + } + else { + /* Finalize the virtual machine. This releases all memory and other + ** resources allocated by the sqlite3_prepare() call above. + */ + closeErrorCode = sqlite3_finalize(pStmt); + } + + if (closeErrorCode != SQLITE_OK) { + if (_logsErrors) { + NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db)); + NSLog(@"DB Query: %@", sql); + } + } + + _isExecutingStatement = NO; + return (rc == SQLITE_DONE || rc == SQLITE_OK); +} + + +- (BOOL)executeUpdate:(NSString*)sql, ... { + va_list args; + va_start(args, sql); + + BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; +} + +- (BOOL)executeUpdate:(NSString*)sql withVAList:(va_list)args { + return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; +} + +- (BOOL)executeUpdateWithFormat:(NSString*)format, ... { + va_list args; + va_start(args, format); + + NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray *arguments = [NSMutableArray array]; + + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; + + va_end(args); + + return [self executeUpdate:sql withArgumentsInArray:arguments]; +} + + +int AWSFMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names); // shhh clang. +int AWSFMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names) { + + if (!theBlockAsVoid) { + return SQLITE_OK; + } + + int (^execCallbackBlock)(NSDictionary *resultsDictionary) = (__bridge int (^)(NSDictionary *__strong))(theBlockAsVoid); + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns]; + + for (NSInteger i = 0; i < columns; i++) { + NSString *key = [NSString stringWithUTF8String:names[i]]; + id value = values[i] ? [NSString stringWithUTF8String:values[i]] : [NSNull null]; + [dictionary setObject:value forKey:key]; + } + + return execCallbackBlock(dictionary); +} + +- (BOOL)executeStatements:(NSString *)sql { + return [self executeStatements:sql withResultBlock:nil]; +} + +- (BOOL)executeStatements:(NSString *)sql withResultBlock:(AWSFMDBExecuteStatementsCallbackBlock)block { + + int rc; + char *errmsg = nil; + + rc = sqlite3_exec([self sqliteHandle], [sql UTF8String], block ? AWSFMDBExecuteBulkSQLCallback : nil, (__bridge void *)(block), &errmsg); + + if (errmsg && [self logsErrors]) { + NSLog(@"Error inserting batch: %s", errmsg); + sqlite3_free(errmsg); + } + + return (rc == SQLITE_OK); +} + +- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { + va_list args; + va_start(args, outErr); + + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; + + va_end(args); + return result; +} + +#pragma clang diagnostic pop + +#pragma mark Transactions + +- (BOOL)rollback { + BOOL b = [self executeUpdate:@"rollback transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)commit { + BOOL b = [self executeUpdate:@"commit transaction"]; + + if (b) { + _inTransaction = NO; + } + + return b; +} + +- (BOOL)beginDeferredTransaction { + + BOOL b = [self executeUpdate:@"begin deferred transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)beginTransaction { + + BOOL b = [self executeUpdate:@"begin exclusive transaction"]; + if (b) { + _inTransaction = YES; + } + + return b; +} + +- (BOOL)inTransaction { + return _inTransaction; +} + +#if SQLITE_VERSION_NUMBER >= 3007000 + +static NSString *AWSFMDBEscapeSavePointName(NSString *savepointName) { + return [savepointName stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; +} + +- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"savepoint '%@';", AWSFMDBEscapeSavePointName(name)]; + + if (![self executeUpdate:sql]) { + + if (outErr) { + *outErr = [self lastError]; + } + + return NO; + } + + return YES; +} + +- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"release savepoint '%@';", AWSFMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr { + + NSParameterAssert(name); + + NSString *sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", AWSFMDBEscapeSavePointName(name)]; + BOOL worked = [self executeUpdate:sql]; + + if (!worked && outErr) { + *outErr = [self lastError]; + } + + return worked; +} + +- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block { + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + NSError *err = 0x00; + + if (![self startSavePointWithName:name error:&err]) { + return err; + } + + if (block) { + block(&shouldRollback); + } + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [self rollbackToSavePointWithName:name error:&err]; + } + [self releaseSavePointWithName:name error:&err]; + + return err; +} + +#endif + +#pragma mark Cache statements + +- (BOOL)shouldCacheStatements { + return _shouldCacheStatements; +} + +- (void)setShouldCacheStatements:(BOOL)value { + + _shouldCacheStatements = value; + + if (_shouldCacheStatements && !_cachedStatements) { + [self setCachedStatements:[NSMutableDictionary dictionary]]; + } + + if (!_shouldCacheStatements) { + [self setCachedStatements:nil]; + } +} + +#pragma mark Callback function + +void AWSFMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv); // -Wmissing-prototypes +void AWSFMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv) { +#if ! __has_feature(objc_arc) + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (id)sqlite3_user_data(context); +#else + void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (__bridge id)sqlite3_user_data(context); +#endif + if (block) { + block(context, argc, argv); + } +} + + +- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(void *context, int argc, void **argv))block { + + if (!_openFunctions) { + _openFunctions = [NSMutableSet new]; + } + + id b = AWSFMDBReturnAutoreleased([block copy]); + + [_openFunctions addObject:b]; + + /* I tried adding custom functions to release the block when the connection is destroyed- but they seemed to never be called, so we use _openFunctions to store the values instead. */ +#if ! __has_feature(objc_arc) + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (void*)b, &AWSFMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#else + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (__bridge void*)b, &AWSFMDBBlockSQLiteCallBackFunction, 0x00, 0x00); +#endif +} + +@end + + + +@implementation AWSFMStatement +@synthesize statement=_statement; +@synthesize query=_query; +@synthesize useCount=_useCount; +@synthesize inUse=_inUse; + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + AWSFMDBRelease(_query); +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + if (_statement) { + sqlite3_finalize(_statement); + _statement = 0x00; + } + + _inUse = NO; +} + +- (void)reset { + if (_statement) { + sqlite3_reset(_statement); + } + + _inUse = NO; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"%@ %ld hit(s) for query %@", [super description], _useCount, _query]; +} + + +@end + diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.h new file mode 100644 index 00000000..28821988 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.h @@ -0,0 +1,277 @@ +// +// FMDatabaseAdditions.h +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import +#import "AWSFMDatabase.h" + + +/** Category of additions for `` class. + + ### See also + + - `` + */ + +@interface AWSFMDatabase (AWSFMDatabaseAdditions) + +///---------------------------------------- +/// @name Return results of SQL to variable +///---------------------------------------- + +/** Return `int` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `int` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (int)intForQuery:(NSString*)query, ...; + +/** Return `long` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `long` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (long)longForQuery:(NSString*)query, ...; + +/** Return `BOOL` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `BOOL` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (BOOL)boolForQuery:(NSString*)query, ...; + +/** Return `double` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `double` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (double)doubleForQuery:(NSString*)query, ...; + +/** Return `NSString` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSString` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (NSString*)stringForQuery:(NSString*)query, ...; + +/** Return `NSData` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSData` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (NSData*)dataForQuery:(NSString*)query, ...; + +/** Return `NSDate` value for query + + @param query The SQL query to be performed. + @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. + + @return `NSDate` value. + + @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. + */ + +- (NSDate*)dateForQuery:(NSString*)query, ...; + + +// Notice that there's no dataNoCopyForQuery:. +// That would be a bad idea, because we close out the result set, and then what +// happens to the data that we just didn't copy? Who knows, not I. + + +///-------------------------------- +/// @name Schema related operations +///-------------------------------- + +/** Does table exist in database? + + @param tableName The name of the table being looked for. + + @return `YES` if table found; `NO` if not found. + */ + +- (BOOL)tableExists:(NSString*)tableName; + +/** The schema of the database. + + This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: + + - `type` - The type of entity (e.g. table, index, view, or trigger) + - `name` - The name of the object + - `tbl_name` - The name of the table to which the object references + - `rootpage` - The page number of the root b-tree page for tables and indices + - `sql` - The SQL that created the entity + + @return `FMResultSet` of schema; `nil` on error. + + @see [SQLite File Format](http://www.sqlite.org/fileformat.html) + */ + +- (AWSFMResultSet*)getSchema; + +/** The schema of the database. + + This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: + + PRAGMA table_info('employees') + + This will report: + + - `cid` - The column ID number + - `name` - The name of the column + - `type` - The data type specified for the column + - `notnull` - whether the field is defined as NOT NULL (i.e. values required) + - `dflt_value` - The default value for the column + - `pk` - Whether the field is part of the primary key of the table + + @param tableName The name of the table for whom the schema will be returned. + + @return `FMResultSet` of schema; `nil` on error. + + @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) + */ + +- (AWSFMResultSet*)getTableSchema:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + */ + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; + +/** Test to see if particular column exists for particular table in database + + @param columnName The name of the column. + + @param tableName The name of the table. + + @return `YES` if column exists in table in question; `NO` otherwise. + + @see columnExists:inTableWithName: + + @warning Deprecated - use `` instead. + */ + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); + + +/** Validate SQL statement + + This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. + + @param sql The SQL statement being validated. + + @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. + + @return `YES` if validation succeeded without incident; `NO` otherwise. + + */ + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; + + +///----------------------------------- +/// @name Application identifier tasks +///----------------------------------- + +/** Retrieve application ID + + @return The `uint32_t` numeric value of the application ID. + + @see setApplicationID: + */ + +- (uint32_t)applicationID; + +/** Set the application ID + + @param appID The `uint32_t` numeric value of the application ID. + + @see applicationID + */ + +- (void)setApplicationID:(uint32_t)appID; + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +/** Retrieve application ID string + + @return The `NSString` value of the application ID. + + @see setApplicationIDString: + */ + + +- (NSString*)applicationIDString; + +/** Set the application ID string + + @param string The `NSString` value of the application ID. + + @see applicationIDString + */ + +- (void)setApplicationIDString:(NSString*)string; +#endif + +///----------------------------------- +/// @name user version identifier tasks +///----------------------------------- + +/** Retrieve user version + + @return The `uint32_t` numeric value of the user version. + + @see setUserVersion: + */ + +- (uint32_t)userVersion; + +/** Set the user-version + + @param version The `uint32_t` numeric value of the user version. + + @see userVersion + */ + +- (void)setUserVersion:(uint32_t)version; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.m b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.m new file mode 100644 index 00000000..0b84c131 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseAdditions.m @@ -0,0 +1,225 @@ +// +// FMDatabaseAdditions.m +// fmdb +// +// Created by August Mueller on 10/30/05. +// Copyright 2005 Flying Meat Inc.. All rights reserved. +// + +#import "AWSFMDatabase.h" +#import "AWSFMDatabaseAdditions.h" +#import "TargetConditionals.h" +#import "AWSFMDatabase+Private.h" + +@interface AWSFMDatabase (PrivateStuff) +- (AWSFMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +@end + +@implementation AWSFMDatabase (AWSFMDatabaseAdditions) + +#define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ +va_list args; \ +va_start(args, query); \ +AWSFMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ +va_end(args); \ +if (![resultSet next]) { return (type)0; } \ +type ret = [resultSet sel:0]; \ +[resultSet close]; \ +[resultSet setParentDB:nil]; \ +return ret; + + +- (NSString*)stringForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); +} + +- (int)intForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); +} + +- (long)longForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); +} + +- (BOOL)boolForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); +} + +- (double)doubleForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); +} + +- (NSData*)dataForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); +} + +- (NSDate*)dateForQuery:(NSString*)query, ... { + RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); +} + + +- (BOOL)tableExists:(NSString*)tableName { + + tableName = [tableName lowercaseString]; + + AWSFMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; + + //if at least one next exists, table exists + BOOL returnBool = [rs next]; + + //close and free object + [rs close]; + + return returnBool; +} + +/* + get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + check if table exist in database (patch from OZLB) +*/ +- (AWSFMResultSet*)getSchema { + + //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + AWSFMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; + + return rs; +} + +/* + get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] +*/ +- (AWSFMResultSet*)getTableSchema:(NSString*)tableName { + + //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] + AWSFMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; + + return rs; +} + +- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { + + BOOL returnBool = NO; + + tableName = [tableName lowercaseString]; + columnName = [columnName lowercaseString]; + + AWSFMResultSet *rs = [self getTableSchema:tableName]; + + //check if column is present in table schema + while ([rs next]) { + if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { + returnBool = YES; + break; + } + } + + //If this is not done FMDatabase instance stays out of pool + [rs close]; + + return returnBool; +} + + +- (uint32_t)applicationID { + +#if SQLITE_VERSION_NUMBER >= 3007017 + uint32_t r = 0; + + AWSFMResultSet *rs = [self executeQuery:@"pragma application_id"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; +#endif + + return r; +} + +- (void)setApplicationID:(uint32_t)appID { +#if SQLITE_VERSION_NUMBER >= 3007017 + NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; + AWSFMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +#endif +} + + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE +- (NSString*)applicationIDString { + NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); + + assert([s length] == 6); + + s = [s substringWithRange:NSMakeRange(1, 4)]; + + + return s; + +} + +- (void)setApplicationIDString:(NSString*)s { + + if ([s length] != 4) { + NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); + } + + [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; +} + +#endif + + +- (uint32_t)userVersion { + uint32_t r = 0; + + AWSFMResultSet *rs = [self executeQuery:@"pragma user_version"]; + + if ([rs next]) { + r = (uint32_t)[rs longLongIntForColumnIndex:0]; + } + + [rs close]; + return r; +} + +- (void)setUserVersion:(uint32_t)version { + NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; + AWSFMResultSet *rs = [self executeQuery:query]; + [rs next]; + [rs close]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { + return [self columnExists:columnName inTableWithName:tableName]; +} + +#pragma clang diagnostic pop + + +- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { + sqlite3_stmt *pStmt = NULL; + BOOL validationSucceeded = YES; + + int rc = sqlite3_prepare_v2(self.db, [sql UTF8String], -1, &pStmt, 0); + if (rc != SQLITE_OK) { + validationSucceeded = NO; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:[self lastErrorCode] + userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] + forKey:NSLocalizedDescriptionKey]]; + } + } + + sqlite3_finalize(pStmt); + + return validationSucceeded; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.h new file mode 100644 index 00000000..397e61dc --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.h @@ -0,0 +1,200 @@ +// +// FMDatabasePool.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import + +@class AWSFMDatabase; + +/** Pool of `` objects. + + ### See also + + - `` + - `` + + @warning Before using `FMDatabasePool`, please consider using `` instead. + + If you really really really know what you're doing and `FMDatabasePool` is what + you really really need (ie, you're using a read only database), OK you can use + it. But just be careful not to deadlock! + + For an example on deadlocking, search for: + `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` + in the main.m file. + */ + +@interface AWSFMDatabasePool : NSObject { + NSString *_path; + + dispatch_queue_t _lockQueue; + + NSMutableArray *_databaseInPool; + NSMutableArray *_databaseOutPool; + + __unsafe_unretained id _delegate; + + NSUInteger _maximumNumberOfDatabasesToCreate; + int _openFlags; +} + +/** Database path */ + +@property (atomic, retain) NSString *path; + +/** Delegate object */ + +@property (atomic, assign) id delegate; + +/** Maximum number of databases to create */ + +@property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + + +///--------------------- +/// @name Initialization +///--------------------- + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create pool using path. + + @param aPath The file path of the database. + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create pool using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabasePool` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +///------------------------------------------------ +/// @name Keeping track of checked in/out databases +///------------------------------------------------ + +/** Number of checked-in databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedInDatabases; + +/** Number of checked-out databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfCheckedOutDatabases; + +/** Total number of databases in pool + + @returns Number of databases + */ + +- (NSUInteger)countOfOpenDatabases; + +/** Release all databases in pool */ + +- (void)releaseAllDatabases; + +///------------------------------------------ +/// @name Perform database operations in pool +///------------------------------------------ + +/** Synchronously perform database operations in pool. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDatabase:(void (^)(AWSFMDatabase *db))block; + +/** Synchronously perform database operations in pool using transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations in pool using deferred transaction. + + @param block The code to be run on the `FMDatabasePool` pool. + */ + +- (void)inDeferredTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations in pool using save point. + + @param block The code to be run on the `FMDatabasePool` pool. + + @return `NSError` object if error; `nil` if successful. + + @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. +*/ + +- (NSError*)inSavePoint:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +@end + + +/** FMDatabasePool delegate category + + This is a category that defines the protocol for the FMDatabasePool delegate + */ + +@interface NSObject (AWSFMDatabasePoolDelegate) + +/** Asks the delegate whether database should be added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + @return `YES` if it should add database to pool; `NO` if not. + + */ + +- (BOOL)databasePool:(AWSFMDatabasePool*)pool shouldAddDatabaseToPool:(AWSFMDatabase*)database; + +/** Tells the delegate that database was added to the pool. + + @param pool The `FMDatabasePool` object. + @param database The `FMDatabase` object. + + */ + +- (void)databasePool:(AWSFMDatabasePool*)pool didAddDatabase:(AWSFMDatabase*)database; + +@end + diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.m b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.m new file mode 100644 index 00000000..93630463 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabasePool.m @@ -0,0 +1,277 @@ +// +// FMDatabasePool.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "AWSFMDatabasePool.h" +#import "AWSFMDatabase.h" +#import "AWSFMDatabase+Private.h" + +@interface AWSFMDatabasePool() + +- (void)pushDatabaseBackInPool:(AWSFMDatabase*)db; +- (AWSFMDatabase*)db; + +@end + + +@implementation AWSFMDatabasePool +@synthesize path=_path; +@synthesize delegate=_delegate; +@synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; +@synthesize openFlags=_openFlags; + + ++ (instancetype)databasePoolWithPath:(NSString*)aPath { + return AWSFMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); +} + ++ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { + return AWSFMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + + self = [super init]; + + if (self != nil) { + _path = [aPath copy]; + _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + _databaseInPool = AWSFMDBReturnRetained([NSMutableArray array]); + _databaseOutPool = AWSFMDBReturnRetained([NSMutableArray array]); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath +{ + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + _delegate = 0x00; + AWSFMDBRelease(_path); + AWSFMDBRelease(_databaseInPool); + AWSFMDBRelease(_databaseOutPool); + + if (_lockQueue) { + AWSFMDBDispatchQueueRelease(_lockQueue); + _lockQueue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + + +- (void)executeLocked:(void (^)(void))aBlock { + dispatch_sync(_lockQueue, aBlock); +} + +- (void)pushDatabaseBackInPool:(AWSFMDatabase*)db { + + if (!db) { // db can be null if we set an upper bound on the # of databases to create. + return; + } + + [self executeLocked:^() { + + if ([self->_databaseInPool containsObject:db]) { + [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; + } + + [self->_databaseInPool addObject:db]; + [self->_databaseOutPool removeObject:db]; + + }]; +} + +- (AWSFMDatabase*)db { + + __block AWSFMDatabase *db; + + + [self executeLocked:^() { + db = [self->_databaseInPool lastObject]; + + BOOL shouldNotifyDelegate = NO; + + if (db) { + [self->_databaseOutPool addObject:db]; + [self->_databaseInPool removeLastObject]; + } + else { + + if (self->_maximumNumberOfDatabasesToCreate) { + NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; + + if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { + NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); + return; + } + } + + db = [AWSFMDatabase databaseWithPath:self->_path]; + shouldNotifyDelegate = YES; + } + + //This ensures that the db is opened before returning +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [db openWithFlags:self->_openFlags]; +#else + BOOL success = [db open]; +#endif + if (success) { + if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { + [db close]; + db = 0x00; + } + else { + //It should not get added in the pool twice if lastObject was found + if (![self->_databaseOutPool containsObject:db]) { + [self->_databaseOutPool addObject:db]; + + if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { + [self->_delegate databasePool:self didAddDatabase:db]; + } + } + } + } + else { + NSLog(@"Could not open up the database at path %@", self->_path); + db = 0x00; + } + }]; + + return db; +} + +- (NSUInteger)countOfCheckedInDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseInPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfCheckedOutDatabases { + + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseOutPool count]; + }]; + + return count; +} + +- (NSUInteger)countOfOpenDatabases { + __block NSUInteger count; + + [self executeLocked:^() { + count = [self->_databaseOutPool count] + [self->_databaseInPool count]; + }]; + + return count; +} + +- (void)releaseAllDatabases { + [self executeLocked:^() { + [self->_databaseOutPool removeAllObjects]; + [self->_databaseInPool removeAllObjects]; + }]; +} + +- (void)inDatabase:(void (^)(AWSFMDatabase *db))block { + + AWSFMDatabase *db = [self db]; + + block(db); + + [self pushDatabaseBackInPool:db]; +} + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + + BOOL shouldRollback = NO; + + AWSFMDatabase *db = [self db]; + + if (useDeferred) { + [db beginDeferredTransaction]; + } + else { + [db beginTransaction]; + } + + + block(db, &shouldRollback); + + if (shouldRollback) { + [db rollback]; + } + else { + [db commit]; + } + + [self pushDatabaseBackInPool:db]; +} + +- (void)inDeferredTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} + +- (NSError*)inSavePoint:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + + NSError *err = 0x00; + +#if SQLITE_VERSION_NUMBER >= 3007000 + + static unsigned long savePointIdx = 0; + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + AWSFMDatabase *db = [self db]; + + if (![db startSavePointWithName:name error:&err]) { + [self pushDatabaseBackInPool:db]; + return err; + } + + block(db, &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [db rollbackToSavePointWithName:name error:&err]; + } + [db releaseSavePointWithName:name error:&err]; + + [self pushDatabaseBackInPool:db]; + +#endif + + return err; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.h new file mode 100644 index 00000000..7a078b79 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.h @@ -0,0 +1,182 @@ +// +// FMDatabaseQueue.h +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import + +@class AWSFMDatabase; + +/** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. + + Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. + + Instead, use `FMDatabaseQueue`. Here's how to use it: + + First, make your queue. + + FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; + + Then use it like so: + + [queue inDatabase:^(FMDatabase *db) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + FMResultSet *rs = [db executeQuery:@"select * from foo"]; + while ([rs next]) { + //… + } + }]; + + An easy way to wrap things up in a transaction can be done like this: + + [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; + + if (whoopsSomethingWrongHappened) { + *rollback = YES; + return; + } + // etc… + [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; + }]; + + `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. + + ### See also + + - `` + + @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. + + @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. + + */ + +@interface AWSFMDatabaseQueue : NSObject { + NSString *_path; + dispatch_queue_t _queue; + AWSFMDatabase *_db; + int _openFlags; +} + +/** Path of database */ + +@property (atomic, retain) NSString *path; + +/** Open flags */ + +@property (atomic, readonly) int openFlags; + +///---------------------------------------------------- +/// @name Initialization, opening, and closing of queue +///---------------------------------------------------- + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create queue using path. + + @param aPath The file path of the database. + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; + +/** Create queue using path and specified flags. + + @param aPath The file path of the database. + @param openFlags Flags passed to the openWithFlags method of the database + @param vfsName The name of a custom virtual file system + + @return The `FMDatabaseQueue` object. `nil` on error. + */ + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName; + +/** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. + + Subclasses can override this method to return specified Class of 'FMDatabase' subclass. + + @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. + */ + ++ (Class)databaseClass; + +/** Close database used by queue. */ + +- (void)close; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations on queue. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDatabase:(void (^)(AWSFMDatabase *db))block; + +/** Synchronously perform database operations on queue, using transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +/** Synchronously perform database operations on queue, using deferred transactions. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +- (void)inDeferredTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +///----------------------------------------------- +/// @name Dispatching database operations to queue +///----------------------------------------------- + +/** Synchronously perform database operations using save point. + + @param block The code to be run on the queue of `FMDatabaseQueue` + */ + +// NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. +// If you need to nest, use FMDatabase's startSavePointWithName:error: instead. +- (NSError*)inSavePoint:(void (^)(AWSFMDatabase *db, BOOL *rollback))block; + +@end + diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.m b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.m new file mode 100644 index 00000000..8a9d2b8c --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMDatabaseQueue.m @@ -0,0 +1,240 @@ +// +// FMDatabaseQueue.m +// fmdb +// +// Created by August Mueller on 6/22/11. +// Copyright 2011 Flying Meat Inc. All rights reserved. +// + +#import "AWSFMDatabaseQueue.h" +#import "AWSFMDatabase.h" +#import "AWSFMDatabase+Private.h" + +/* + + Note: we call [self retain]; before using dispatch_sync, just incase + FMDatabaseQueue is released on another thread and we're in the middle of doing + something in dispatch_sync + + */ + +/* + * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. + * This in turn is used for deadlock detection by seeing if inDatabase: is called on + * the queue's dispatch queue, which should not happen and causes a deadlock. + */ +static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; + +@implementation AWSFMDatabaseQueue + +@synthesize path = _path; +@synthesize openFlags = _openFlags; + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath { + + AWSFMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; + + AWSFMDBAutorelease(q); + + return q; +} + ++ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { + + AWSFMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; + + AWSFMDBAutorelease(q); + + return q; +} + ++ (Class)databaseClass { + return [AWSFMDatabase class]; +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { + + self = [super init]; + + if (self != nil) { + + _db = [[[self class] databaseClass] databaseWithPath:aPath]; + AWSFMDBRetain(_db); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; +#else + BOOL success = [_db open]; +#endif + if (!success) { + NSLog(@"Could not create database queue for path %@", aPath); + AWSFMDBRelease(self); + return 0x00; + } + + _path = AWSFMDBReturnRetained(aPath); + + _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); + dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); + _openFlags = openFlags; + } + + return self; +} + +- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { + return [self initWithPath:aPath flags:openFlags vfs:nil]; +} + +- (instancetype)initWithPath:(NSString*)aPath { + + // default flags for sqlite3_open + return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; +} + +- (instancetype)init { + return [self initWithPath:nil]; +} + + +- (void)dealloc { + + AWSFMDBRelease(_db); + AWSFMDBRelease(_path); + + if (_queue) { + AWSFMDBDispatchQueueRelease(_queue); + _queue = 0x00; + } +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + AWSFMDBRetain(self); + dispatch_sync(_queue, ^() { + [self->_db close]; + AWSFMDBRelease(_db); + self->_db = 0x00; + }); + AWSFMDBRelease(self); +} + +- (AWSFMDatabase*)database { + if (!_db) { + _db = AWSFMDBReturnRetained([AWSFMDatabase databaseWithPath:_path]); + +#if SQLITE_VERSION_NUMBER >= 3005000 + BOOL success = [_db openWithFlags:_openFlags]; +#else + BOOL success = [_db open]; +#endif + if (!success) { + NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); + AWSFMDBRelease(_db); + _db = 0x00; + return 0x00; + } + } + + return _db; +} + +- (void)inDatabase:(void (^)(AWSFMDatabase *db))block { + /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue + * and then check it against self to make sure we're not about to deadlock. */ + AWSFMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); + assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); + + AWSFMDBRetain(self); + + dispatch_sync(_queue, ^() { + + AWSFMDatabase *db = [self database]; + block(db); + + if ([db hasOpenResultSets]) { + NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); + +#if defined(DEBUG) && DEBUG + NSSet *openSetCopy = AWSFMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); + for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { + AWSFMResultSet *rs = (AWSFMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + NSLog(@"query: '%@'", [rs query]); + } +#endif + } + }); + + AWSFMDBRelease(self); +} + + +- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + AWSFMDBRetain(self); + dispatch_sync(_queue, ^() { + + BOOL shouldRollback = NO; + + if (useDeferred) { + [[self database] beginDeferredTransaction]; + } + else { + [[self database] beginTransaction]; + } + + block([self database], &shouldRollback); + + if (shouldRollback) { + [[self database] rollback]; + } + else { + [[self database] commit]; + } + }); + + AWSFMDBRelease(self); +} + +- (void)inDeferredTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + [self beginTransaction:YES withBlock:block]; +} + +- (void)inTransaction:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + [self beginTransaction:NO withBlock:block]; +} + +- (NSError*)inSavePoint:(void (^)(AWSFMDatabase *db, BOOL *rollback))block { + + __block NSError *err = 0x00; + +#if SQLITE_VERSION_NUMBER >= 3007000 + + static unsigned long savePointIdx = 0; + AWSFMDBRetain(self); + dispatch_sync(_queue, ^() { + + NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + + BOOL shouldRollback = NO; + + if ([[self database] startSavePointWithName:name error:&err]) { + + block([self database], &shouldRollback); + + if (shouldRollback) { + // We need to rollback and release this savepoint to remove it + [[self database] rollbackToSavePointWithName:name error:&err]; + } + [[self database] releaseSavePointWithName:name error:&err]; + + } + }); + AWSFMDBRelease(self); + +#endif + return err; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.h b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.h new file mode 100644 index 00000000..f92568d5 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.h @@ -0,0 +1,468 @@ +#import + +#ifndef __has_feature // Optional. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_NOT_RETAINED +#if __has_feature(attribute_ns_returns_not_retained) +#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) +#else +#define NS_RETURNS_NOT_RETAINED +#endif +#endif + +@class AWSFMDatabase; +@class AWSFMStatement; + +/** Represents the results of executing a query on an ``. + + ### See also + + - `` + */ + +@interface AWSFMResultSet : NSObject { + AWSFMDatabase *_parentDB; + AWSFMStatement *_statement; + + NSString *_query; + NSMutableDictionary *_columnNameToIndexMap; +} + +///----------------- +/// @name Properties +///----------------- + +/** Executed query */ + +@property (atomic, retain) NSString *query; + +/** `NSMutableDictionary` mapping column names to numeric index */ + +@property (readonly) NSMutableDictionary *columnNameToIndexMap; + +/** `FMStatement` used by result set. */ + +@property (atomic, retain) AWSFMStatement *statement; + +///------------------------------------ +/// @name Creating and closing database +///------------------------------------ + +/** Create result set from `` + + @param statement A `` to be performed + + @param aDB A `` to be used + + @return A `FMResultSet` on success; `nil` on failure + */ + ++ (instancetype)resultSetWithStatement:(AWSFMStatement *)statement usingParentDatabase:(AWSFMDatabase*)aDB; + +/** Close result set */ + +- (void)close; + +- (void)setParentDB:(AWSFMDatabase *)newDb; + +///--------------------------------------- +/// @name Iterating through the result set +///--------------------------------------- + +/** Retrieve next row for result set. + + You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. + + @return `YES` if row successfully retrieved; `NO` if end of result set reached + + @see hasAnotherRow + */ + +- (BOOL)next; + +/** Retrieve next row for result set. + + You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. + + @param outErr A 'NSError' object to receive any error object (if any). + + @return 'YES' if row successfully retrieved; 'NO' if end of result set reached + + @see hasAnotherRow + */ + +- (BOOL)nextWithError:(NSError **)outErr; + +/** Did the last call to `` succeed in retrieving another row? + + @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. + + @see next + + @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. + */ + +- (BOOL)hasAnotherRow; + +///--------------------------------------------- +/// @name Retrieving information from result set +///--------------------------------------------- + +/** How many columns in result set + + @return Integer value of the number of columns. + */ + +- (int)columnCount; + +/** Column index for column name + + @param columnName `NSString` value of the name of the column. + + @return Zero-based index for column. + */ + +- (int)columnIndexForName:(NSString*)columnName; + +/** Column name for column index + + @param columnIdx Zero-based index for column. + + @return columnName `NSString` value of the name of the column. + */ + +- (NSString*)columnNameForIndex:(int)columnIdx; + +/** Result set integer value for column. + + @param columnName `NSString` value of the name of the column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumn:(NSString*)columnName; + +/** Result set integer value for column. + + @param columnIdx Zero-based index for column. + + @return `int` value of the result set's column. + */ + +- (int)intForColumnIndex:(int)columnIdx; + +/** Result set `long` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumn:(NSString*)columnName; + +/** Result set long value for column. + + @param columnIdx Zero-based index for column. + + @return `long` value of the result set's column. + */ + +- (long)longForColumnIndex:(int)columnIdx; + +/** Result set `long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumn:(NSString*)columnName; + +/** Result set `long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `long long int` value of the result set's column. + */ + +- (long long int)longLongIntForColumnIndex:(int)columnIdx; + +/** Result set `unsigned long long int` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; + +/** Result set `unsigned long long int` value for column. + + @param columnIdx Zero-based index for column. + + @return `unsigned long long int` value of the result set's column. + */ + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; + +/** Result set `BOOL` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumn:(NSString*)columnName; + +/** Result set `BOOL` value for column. + + @param columnIdx Zero-based index for column. + + @return `BOOL` value of the result set's column. + */ + +- (BOOL)boolForColumnIndex:(int)columnIdx; + +/** Result set `double` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumn:(NSString*)columnName; + +/** Result set `double` value for column. + + @param columnIdx Zero-based index for column. + + @return `double` value of the result set's column. + + */ + +- (double)doubleForColumnIndex:(int)columnIdx; + +/** Result set `NSString` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSString` value of the result set's column. + + */ + +- (NSString*)stringForColumn:(NSString*)columnName; + +/** Result set `NSString` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSString` value of the result set's column. + */ + +- (NSString*)stringForColumnIndex:(int)columnIdx; + +/** Result set `NSDate` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSDate` value of the result set's column. + */ + +- (NSDate*)dateForColumn:(NSString*)columnName; + +/** Result set `NSDate` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSDate` value of the result set's column. + + */ + +- (NSDate*)dateForColumnIndex:(int)columnIdx; + +/** Result set `NSData` value for column. + + This is useful when storing binary data in table (such as image or the like). + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + */ + +- (NSData*)dataForColumn:(NSString*)columnName; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + */ + +- (NSData*)dataForColumnIndex:(int)columnIdx; + +/** Result set `(const unsigned char *)` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; + +/** Result set `(const unsigned char *)` value for column. + + @param columnIdx Zero-based index for column. + + @return `(const unsigned char *)` value of the result set's column. + */ + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectForKeyedSubscript: + */ + +- (id)objectForColumnName:(NSString*)columnName; + +/** Result set object for column. + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + + @see objectAtIndexedSubscript: + */ + +- (id)objectForColumnIndex:(int)columnIdx; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[@"employee_name"]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:@"employee_name"]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:@"employee_name"]; + + @param columnName `NSString` value of the name of the column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectForKeyedSubscript:(NSString *)columnName; + +/** Result set object for column. + + This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: + + id result = rs[0]; + + This simplified syntax is equivalent to calling: + + id result = [rs objectForKeyedSubscript:0]; + + which is, it turns out, equivalent to calling: + + id result = [rs objectForColumnName:0]; + + @param columnIdx Zero-based index for column. + + @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. + */ + +- (id)objectAtIndexedSubscript:(int)columnIdx; + +/** Result set `NSData` value for column. + + @param columnName `NSString` value of the name of the column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the +result set, make sure to make a copy of the data first (or just use ``/``) +If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; + +/** Result set `NSData` value for column. + + @param columnIdx Zero-based index for column. + + @return `NSData` value of the result set's column. + + @warning If you are going to use this data after you iterate over the next row, or after you close the + result set, make sure to make a copy of the data first (or just use ``/``) + If you don't, you're going to be in a world of hurt when you try and use the data. + + */ + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; + +/** Is the column `NULL`? + + @param columnIdx Zero-based index for column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIndexIsNull:(int)columnIdx; + +/** Is the column `NULL`? + + @param columnName `NSString` value of the name of the column. + + @return `YES` if column is `NULL`; `NO` if not `NULL`. + */ + +- (BOOL)columnIsNull:(NSString*)columnName; + + +/** Returns a dictionary of the row results mapped to case sensitive keys of the column names. + + @returns `NSDictionary` of the row results. + + @warning The keys to the dictionary are case sensitive of the column names. + */ + +- (NSDictionary*)resultDictionary; + +/** Returns a dictionary of the row results + + @see resultDictionary + + @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! + */ + +- (NSDictionary*)resultDict __attribute__ ((deprecated)); + +///----------------------------- +/// @name Key value coding magic +///----------------------------- + +/** Performs `setValue` to yield support for key value observing. + + @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. + + */ + +- (void)kvcMagic:(id)object; + + +@end + diff --git a/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.m b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.m new file mode 100644 index 00000000..8fdd3131 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/FMDB/AWSFMResultSet.m @@ -0,0 +1,417 @@ +#import "AWSFMResultSet.h" +#import "AWSFMDatabase.h" +#import "unistd.h" +#import "AWSFMDatabase+Private.h" + +@interface AWSFMDatabase () +- (void)resultSetDidClose:(AWSFMResultSet *)resultSet; +@end + + +@implementation AWSFMResultSet +@synthesize query=_query; +@synthesize statement=_statement; + ++ (instancetype)resultSetWithStatement:(AWSFMStatement *)statement usingParentDatabase:(AWSFMDatabase*)aDB { + + AWSFMResultSet *rs = [[AWSFMResultSet alloc] init]; + + [rs setStatement:statement]; + [rs setParentDB:aDB]; + + NSParameterAssert(![statement inUse]); + [statement setInUse:YES]; // weak reference + + return AWSFMDBReturnAutoreleased(rs); +} + +- (void)finalize { + [self close]; + [super finalize]; +} + +- (void)dealloc { + [self close]; + + AWSFMDBRelease(_query); + _query = nil; + + AWSFMDBRelease(_columnNameToIndexMap); + _columnNameToIndexMap = nil; + +#if ! __has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (void)close { + [_statement reset]; + AWSFMDBRelease(_statement); + _statement = nil; + + // we don't need this anymore... (i think) + //[_parentDB setInUse:NO]; + [_parentDB resultSetDidClose:self]; + _parentDB = nil; +} + +- (int)columnCount { + return sqlite3_column_count([_statement statement]); +} + +- (NSMutableDictionary *)columnNameToIndexMap { + if (!_columnNameToIndexMap) { + int columnCount = sqlite3_column_count([_statement statement]); + _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] + forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; + } + } + return _columnNameToIndexMap; +} + +- (void)kvcMagic:(id)object { + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + // check for a null row + if (c) { + NSString *s = [NSString stringWithUTF8String:c]; + + [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; + } + } +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (NSDictionary*)resultDict { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; + NSString *columnName = nil; + while ((columnName = [columnNames nextObject])) { + id objectValue = [self objectForColumnName:columnName]; + [dict setObject:objectValue forKey:columnName]; + } + + return AWSFMDBReturnAutoreleased([dict copy]); + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + +#pragma clang diagnostic pop + +- (NSDictionary*)resultDictionary { + + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); + + if (num_cols > 0) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + + int columnCount = sqlite3_column_count([_statement statement]); + + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { + + NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; + id objectValue = [self objectForColumnIndex:columnIdx]; + [dict setObject:objectValue forKey:columnName]; + } + + return dict; + } + else { + NSLog(@"Warning: There seem to be no columns in this set."); + } + + return nil; +} + + + + +- (BOOL)next { + return [self nextWithError:nil]; +} + +- (BOOL)nextWithError:(NSError **)outErr { + + int rc = sqlite3_step([_statement statement]); + + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { + NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); + NSLog(@"Database busy"); + if (outErr) { + *outErr = [_parentDB lastError]; + } + } + else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { + // all is well, let's return. + } + else if (SQLITE_ERROR == rc) { + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + if (outErr) { + *outErr = [_parentDB lastError]; + } + } + else if (SQLITE_MISUSE == rc) { + // uh oh. + NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + if (outErr) { + if (_parentDB) { + *outErr = [_parentDB lastError]; + } + else { + // If 'next' or 'nextWithError' is called after the result set is closed, + // we need to return the appropriate error. + NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; + *outErr = [NSError errorWithDomain:@"AWSFMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; + } + + } + } + else { + // wtf? + NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + if (outErr) { + *outErr = [_parentDB lastError]; + } + } + + + if (rc != SQLITE_ROW) { + [self close]; + } + + return (rc == SQLITE_ROW); +} + +- (BOOL)hasAnotherRow { + return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; +} + +- (int)columnIndexForName:(NSString*)columnName { + columnName = [columnName lowercaseString]; + + NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; + + if (n) { + return [n intValue]; + } + + NSLog(@"Warning: I could not find the column named '%@'.", columnName); + + return -1; +} + + + +- (int)intForColumn:(NSString*)columnName { + return [self intForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (int)intForColumnIndex:(int)columnIdx { + return sqlite3_column_int([_statement statement], columnIdx); +} + +- (long)longForColumn:(NSString*)columnName { + return [self longForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long)longForColumnIndex:(int)columnIdx { + return (long)sqlite3_column_int64([_statement statement], columnIdx); +} + +- (long long int)longLongIntForColumn:(NSString*)columnName { + return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long long int)longLongIntForColumnIndex:(int)columnIdx { + return sqlite3_column_int64([_statement statement], columnIdx); +} + +- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { + return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { + return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; +} + +- (BOOL)boolForColumn:(NSString*)columnName { + return [self boolForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (BOOL)boolForColumnIndex:(int)columnIdx { + return ([self intForColumnIndex:columnIdx] != 0); +} + +- (double)doubleForColumn:(NSString*)columnName { + return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (double)doubleForColumnIndex:(int)columnIdx { + return sqlite3_column_double([_statement statement], columnIdx); +} + +- (NSString*)stringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + + if (!c) { + // null row. + return nil; + } + + return [NSString stringWithUTF8String:c]; +} + +- (NSString*)stringForColumn:(NSString*)columnName { + return [self stringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumn:(NSString*)columnName { + return [self dateForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate*)dateForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; +} + + +- (NSData*)dataForColumn:(NSString*)columnName { + return [self dataForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + + if (dataBuffer == NULL) { + return nil; + } + + return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; +} + + +- (NSData*)dataNoCopyForColumn:(NSString*)columnName { + return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); + int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); + + NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; + + return data; +} + + +- (BOOL)columnIndexIsNull:(int)columnIdx { + return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; +} + +- (BOOL)columnIsNull:(NSString*)columnName { + return [self columnIndexIsNull:[self columnIndexForName:columnName]]; +} + +- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { + + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { + return nil; + } + + return sqlite3_column_text([_statement statement], columnIdx); +} + +- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { + return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (id)objectForColumnIndex:(int)columnIdx { + int columnType = sqlite3_column_type([_statement statement], columnIdx); + + id returnValue = nil; + + if (columnType == SQLITE_INTEGER) { + returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_FLOAT) { + returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; + } + else if (columnType == SQLITE_BLOB) { + returnValue = [self dataForColumnIndex:columnIdx]; + } + else { + //default to a string for everything else + returnValue = [self stringForColumnIndex:columnIdx]; + } + + if (returnValue == nil) { + returnValue = [NSNull null]; + } + + return returnValue; +} + +- (id)objectForColumnName:(NSString*)columnName { + return [self objectForColumnIndex:[self columnIndexForName:columnName]]; +} + +// returns autoreleased NSString containing the name of the column in the result set +- (NSString*)columnNameForIndex:(int)columnIdx { + return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; +} + +- (void)setParentDB:(AWSFMDatabase *)newDb { + _parentDB = newDb; +} + +- (id)objectAtIndexedSubscript:(int)columnIdx { + return [self objectForColumnIndex:columnIdx]; +} + +- (id)objectForKeyedSubscript:(NSString *)columnName { + return [self objectForColumnName:columnName]; +} + + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Fabric/FABAttributes.h b/ios/Pods/AWSCore/AWSCore/Fabric/FABAttributes.h new file mode 100644 index 00000000..e35f9ce3 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Fabric/FABAttributes.h @@ -0,0 +1,60 @@ +// +// FABAttributes.h +// Fabric +// +// Copyright (C) 2015 Twitter, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#pragma once + +#define FAB_UNAVAILABLE(x) __attribute__((unavailable(x))) + +#if __has_feature(nullability) + #define fab_nullable nullable + #define fab_nonnull nonnull + #define fab_null_unspecified null_unspecified + #define fab_null_resettable null_resettable + #define __fab_nullable __nullable + #define __fab_nonnull __nonnull + #define __fab_null_unspecified __null_unspecified +#else + #define fab_nullable + #define fab_nonnull + #define fab_null_unspecified + #define fab_null_resettable + #define __fab_nullable + #define __fab_nonnull + #define __fab_null_unspecified +#endif + +#ifndef NS_ASSUME_NONNULL_BEGIN + #define NS_ASSUME_NONNULL_BEGIN +#endif + +#ifndef NS_ASSUME_NONNULL_END + #define NS_ASSUME_NONNULL_END +#endif + + +/** + * The following macros are defined here to provide + * backwards compatability. If you are still using + * them you should migrate to the new versions that + * are defined above. + */ +#define FAB_NONNULL __fab_nonnull +#define FAB_NULLABLE __fab_nullable +#define FAB_START_NONNULL NS_ASSUME_NONNULL_BEGIN +#define FAB_END_NONNULL NS_ASSUME_NONNULL_END diff --git a/ios/Pods/AWSCore/AWSCore/Fabric/FABKitProtocol.h b/ios/Pods/AWSCore/AWSCore/Fabric/FABKitProtocol.h new file mode 100644 index 00000000..f24ab4bd --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Fabric/FABKitProtocol.h @@ -0,0 +1,59 @@ +// +// FABKitProtocol.h +// Fabric +// +// Copyright (C) 2015 Twitter, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + * Protocol that a class in a Fabric Kit must conform to to provide information to Fabric at runtime. + */ +@protocol FABKit + +@required + +/** + * Required. The globally unique identifier of the Kit. + * We encourage the use of reverse-DNS notation. + * Example: @"io.fabric.sdk.ios" + */ ++ (NSString *)bundleIdentifier; + +/** + * Required. Must return the current version of the Kit that is being used at runtime. + * We encourage the use of semantic versioning (http://semver.org/), without prefixing the version with a "v". + * This is commonly referred to as the "marketing version". + * Example: @"1.2.3" + */ ++ (NSString *)kitDisplayVersion; + +@optional + +/** + * The build version of the kit. Should be monotonically increasing and unique. + * Example: 137 + */ ++ (NSString *)kitBuildVersion; + +/** + * Perform any necessary initialization. + * This method will be invoked on the Kit when the user calls +[Fabric initializeKits]. + * @note This method being called does not necessarily imply that the developer has started using the Kit yet. + */ ++ (void)initializeIfNeeded; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Fabric/Fabric+FABKits.h b/ios/Pods/AWSCore/AWSCore/Fabric/Fabric+FABKits.h new file mode 100644 index 00000000..5493ceb7 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Fabric/Fabric+FABKits.h @@ -0,0 +1,38 @@ +// +// Fabric+FABKits.h +// Fabric +// +// Copyright (C) 2015 Twitter, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "Fabric.h" + +@protocol FABKit; +// Use this category for methods that kits can call on Fabric. +@interface Fabric (FABKits) + +/** + * Returns a dictionary containing the kit configuration info for the provided kit. + * The configuration information is parsed from the application's Info.plist. This + * method is primarily intended to be used by kits to retrieve their configuration. + * + * @param kitClass The class of the kit whose configuration should be returned. + * It should conform to the FABKit protocol. + * + * @return A dictionary containing kit specific configuration information or nil if none exists. + */ ++ (fab_nonnull NSDictionary *)configurationDictionaryForKitClass:(fab_nonnull Class)kitClass; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Fabric/Fabric.h b/ios/Pods/AWSCore/AWSCore/Fabric/Fabric.h new file mode 100644 index 00000000..54f3bc52 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Fabric/Fabric.h @@ -0,0 +1,67 @@ +// +// Fabric.h +// Fabric +// +// Copyright (C) 2015 Twitter, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "FABAttributes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Fabric Base. Coordinates configuration and starts all provided kits. + */ +@interface Fabric : NSObject + +/** + * Initialize Fabric and all provided kits. Call this method within your App Delegate's `application:didFinishLaunchingWithOptions:` and provide the kits you wish to use. + * + * For example, in Objective-C: + * + * `[Fabric with:@[[Crashlytics class], [Twitter class], [Digits class], [MoPub class]]];` + * + * Swift: + * + * `Fabric.with([Crashlytics.self(), Twitter.self(), Digits.self(), MoPub.self()])` + * + * Only the first call to this method is honored. Subsequent calls are no-ops. + * + * @param kits An array of kit Class objects + * + * @return Returns the shared Fabric instance. In most cases this can be ignored. + */ ++ (instancetype)with:(NSArray *)kitClasses; + +/** + * Returns the Fabric singleton object. + */ ++ (instancetype)sharedSDK; + +/** + * This BOOL enables or disables debug logging, such as kit version information. The default value is NO. + */ +@property (nonatomic, assign) BOOL debug; + +/** + * Unavailable. Use `+sharedSDK` to retrieve the shared Fabric instance. + */ +- (id)init FAB_UNAVAILABLE("Use +sharedSDK to retrieve the shared Fabric instance."); + +@end + +NS_ASSUME_NONNULL_END + diff --git a/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.h b/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.h new file mode 100644 index 00000000..bd1dce4b --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.h @@ -0,0 +1,44 @@ +// +// GZIP.h +// +// Version 1.0.3 +// +// Created by Nick Lockwood on 03/06/2012. +// Copyright (C) 2012 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/GZIP +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#import + +void awsgzip_loadGZIP(); + +@interface NSData (AWSGZIP) + +- (NSData *)awsgzip_gzippedDataWithCompressionLevel:(float)level; +- (NSData *)awsgzip_gzippedData; +- (NSData *)awsgzip_gunzippedData; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.m b/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.m new file mode 100644 index 00000000..14f55d5e --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/GZIP/AWSGZIP.m @@ -0,0 +1,124 @@ +// +// GZIP.m +// +// Version 1.0.3 +// +// Created by Nick Lockwood on 03/06/2012. +// Copyright (C) 2012 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/GZIP +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#import "AWSGZIP.h" +#import + +void awsgzip_loadGZIP(){ +} + +static const NSUInteger ChunkSize = 16384; + + +@implementation NSData (AWSGZIP) + +- (NSData *)awsgzip_gzippedDataWithCompressionLevel:(float)level +{ + if ([self length]) + { + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = (uint)[self length]; + stream.next_in = (Bytef *)[self bytes]; + stream.total_out = 0; + stream.avail_out = 0; + + int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9)); + if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) + { + NSMutableData *data = [NSMutableData dataWithLength:ChunkSize]; + while (stream.avail_out == 0) + { + if (stream.total_out >= [data length]) + { + data.length += ChunkSize; + } + stream.next_out = (uint8_t *)[data mutableBytes] + stream.total_out; + stream.avail_out = (uInt)([data length] - stream.total_out); + deflate(&stream, Z_FINISH); + } + deflateEnd(&stream); + data.length = stream.total_out; + return data; + } + } + return nil; +} + +- (NSData *)awsgzip_gzippedData +{ + return [self awsgzip_gzippedDataWithCompressionLevel:-1.0f]; +} + +- (NSData *)awsgzip_gunzippedData +{ + if ([self length]) + { + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.avail_in = (uint)[self length]; + stream.next_in = (Bytef *)[self bytes]; + stream.total_out = 0; + stream.avail_out = 0; + + NSMutableData *data = [NSMutableData dataWithLength:(NSUInteger)([self length] * 1.5)]; + if (inflateInit2(&stream, 47) == Z_OK) + { + int status = Z_OK; + while (status == Z_OK) + { + if (stream.total_out >= [data length]) + { + data.length += [self length] / 2; + } + stream.next_out = (uint8_t *)[data mutableBytes] + stream.total_out; + stream.avail_out = (uInt)([data length] - stream.total_out); + status = inflate (&stream, Z_SYNC_FLUSH); + } + if (inflateEnd(&stream) == Z_OK) + { + if (status == Z_STREAM_END) + { + data.length = stream.total_out; + return data; + } + } + } + } + return nil; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.h b/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.h new file mode 100644 index 00000000..6ed1f245 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.h @@ -0,0 +1,204 @@ +// +// KSReachability.h +// +// Created by Karl Stenerud on 5/5/12. +// +// Copyright (c) 2012 Karl Stenerud. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import +#import + + +/** This is the notification name used in the Apple reachability example. + * It is not used internally, and is merely a suggested notification name. + */ +#define kAWSDefaultNetworkReachabilityChangedNotification @"kAWSNetworkReachabilityChangedNotification" + + +@class AWSKSReachability; + +typedef void(^AWSKSReachabilityCallback)(AWSKSReachability* reachability); + + +/** Monitors network connectivity. + * + * You can elect to be notified via blocks (onReachabilityChanged), + * notifications (notificationName), or KVO (flags, reachable, and WWANOnly). + * + * All notification methods are disabled by default. + * + * Note: Upon construction, this object will fetch its initial reachability + * state in the background. This means that the reachability status will ALWAYS + * be "unreachable" until some time after object construction (possibly up to 10 + * seconds, depending on how long the DNS lookup takes). Use the "initialized" + * property to monitor initialization, or set the callback "onInitializationComplete". + */ +@interface AWSKSReachability : NSObject + +#pragma mark Constructors + +/** Reachability to a specific host. Returns nil if an initialization error occurs. + * + * @param hostname The name or IP address of the host to monitor. If nil or + * empty string, check reachability to the internet in general. + */ ++ (AWSKSReachability*) reachabilityToHost:(NSString*) hostname; + +/** Reachability to the local (wired or wifi) network. Returns nil if an initialization error occurs. + */ ++ (AWSKSReachability*) reachabilityToLocalNetwork; + +/** Reachability to the internet. Returns nil if an initialization error occurs. + */ ++ (AWSKSReachability*) reachabilityToInternet; + + +#pragma mark General Information + +/** The host we are monitoring reachability to, if any. */ +@property(nonatomic,readonly,retain) NSString* hostname; + + +#pragma mark Notifications and Callbacks + +/** If non-nil, called when the KSReachability object has finished initializing. + * If initialization has already completed, calls on the next main thread run loop. + * This block will only be called once, and then discarded (released). + * Block will be invoked on the main thread. + */ +@property(atomic,readwrite,copy) AWSKSReachabilityCallback onInitializationComplete; + +/** If non-nil, called whenever reachability flags change. + * Block will be invoked on the main thread. + */ +@property(atomic,readwrite,copy) AWSKSReachabilityCallback onReachabilityChanged; + +/** The notification to send when reachability changes (nil = don't send). + * Default = nil + */ +@property(nonatomic,readwrite,retain) NSString* notificationName; + + +#pragma mark KVO Compliant Status Properties + +/** The current reachability flags. + * This property will always report 0 while "initialized" property = NO. + */ +@property(nonatomic,readonly,assign) SCNetworkReachabilityFlags flags; + +/** Whether the host is reachable or not. + * This property will always report NO while "initialized" property = NO. + */ +@property(nonatomic,readonly,assign) BOOL reachable; + +/* If YES, the host is only reachable by WWAN (iOS only). + * This property will always report NO while "initialized" property = NO. + */ +@property(nonatomic,readonly,assign) BOOL WWANOnly; + +/** If YES, this object's status properties are valid. */ +@property(atomic,readonly,assign) BOOL initialized; + +@end + + + +/** A one-time operation to perform as soon as a host is deemed reachable. + * The operation will only be performed once, regardless of how many times a + * host becomes reachable. + */ +@interface AWSKSReachableOperation: NSObject + +/** Constructor. Returns nil if an initialization error occurs. + * + * @param hostname The name or IP address of the host to monitor. If nil or + * empty string, check reachability to the internet in general. + * If hostname is a URL string, it will use the host portion. + * + * @param allowWWAN If NO, a WWAN-only connection is not enough to trigger + * this operation. + * + * @param onReachabilityAchieved Invoke when the host becomes reachable. + * This will be invoked ONE TIME ONLY, no matter + * how many times reachability changes. + * Block will be invoked on the main thread. + */ ++ (AWSKSReachableOperation*) operationWithHost:(NSString*) hostname + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved; + +/** Constructor. Returns nil if an initialization error occurs. + * + * @param reachability A reachability instance. Note: This object will overwrite + * the onReachabilityChanged property. + * + * @param allowWWAN If NO, a WWAN-only connection is not enough to trigger + * this operation. + * + * @param onReachabilityAchieved Invoke when the host becomes reachable. + * This will be invoked ONE TIME ONLY, no matter + * how many times reachability changes. + * Block will be invoked on the main thread. + */ ++ (AWSKSReachableOperation*) operationWithReachability:(AWSKSReachability*) reachability + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved; + +/** Initializer. Returns nil if an initialization error occurs. + * + * @param hostname The name or IP address of the host to monitor. If nil or + * empty string, check reachability to the internet in general. + * If hostname is a URL string, it will use the host portion. + * + * @param allowWWAN If NO, a WWAN-only connection is not enough to trigger + * this operation. + * + * @param onReachabilityAchieved Invoke when the host becomes reachable. + * This will be invoked ONE TIME ONLY, no matter + * how many times reachability changes. + * Block will be invoked on the main thread. + */ +- (id) initWithHost:(NSString*) hostname + allowWWAN:(BOOL) allowWWAN +onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved; + +/** Initializer. Returns nil if an initialization error occurs. + * + * @param reachability A reachability instance. Note: This object will overwrite + * the onReachabilityChanged property. + * + * @param allowWWAN If NO, a WWAN-only connection is not enough to trigger + * this operation. + * + * @param onReachabilityAchieved Invoke when the host becomes reachable. + * This will be invoked ONE TIME ONLY, no matter + * how many times reachability changes. + * Block will be invoked on the main thread. + */ +- (id) initWithReachability:(AWSKSReachability*) reachability + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved; + +/** Access to internal reachability instance. Use this to monitor for errors. */ +@property(nonatomic,readonly,retain) AWSKSReachability* reachability; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.m b/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.m new file mode 100644 index 00000000..a63bb4d7 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/KSReachability/AWSKSReachability.m @@ -0,0 +1,461 @@ +// +// KSReachability.m +// +// Created by Karl Stenerud on 5/5/12. +// +// Copyright (c) 2012 Karl Stenerud. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "AWSKSReachability.h" +#import +#import + + +// ---------------------------------------------------------------------- +#pragma mark - ARC-Safe Memory Management - +// ---------------------------------------------------------------------- + +// Full version at https://github.com/kstenerud/ARCSafe-MemManagement +#if __has_feature(objc_arc) + #define aws_as_release(X) + #define aws_as_autorelease(X) (X) + #define aws_as_autorelease_noref(X) + #define aws_as_superdealloc() + #define aws_as_bridge __bridge +#else + #define aws_as_release(X) [(X) release] + #define aws_as_autorelease(X) [(X) autorelease] + #define aws_as_autorelease_noref(X) [(X) autorelease] + #define aws_as_superdealloc() [super dealloc] + #define aws_as_bridge +#endif + + +#define kAWSKVOProperty_Flags @"flags" +#define kAWSKVOProperty_Reachable @"reachable" +#define kAWSKVOProperty_WWANOnly @"WWANOnly" + + +// ---------------------------------------------------------------------- +#pragma mark - KSReachability - +// ---------------------------------------------------------------------- + +@interface AWSKSReachability () + +@property(nonatomic,readwrite,retain) NSString* hostname; +@property(nonatomic,readwrite,assign) SCNetworkReachabilityFlags flags; +@property(nonatomic,readwrite,assign) BOOL reachable; +@property(nonatomic,readwrite,assign) BOOL WWANOnly; +@property(nonatomic,readwrite,assign) SCNetworkReachabilityRef reachabilityRef; +@property(atomic,readwrite,assign) BOOL initialized; + +@end + +static void onReachabilityChanged(SCNetworkReachabilityRef target, + SCNetworkReachabilityFlags flags, + void* info); + + +@implementation AWSKSReachability + +@synthesize onInitializationComplete = _onInitializationComplete; +@synthesize onReachabilityChanged = _onReachabilityChanged; +@synthesize flags = _flags; +@synthesize reachable = _reachable; +@synthesize WWANOnly = _WWANOnly; +@synthesize reachabilityRef = _reachabilityRef; +@synthesize hostname = _hostname; +@synthesize notificationName = _notificationName; +@synthesize initialized = _initialized; + ++ (AWSKSReachability*) reachabilityToHost:(NSString*) hostname +{ + return aws_as_autorelease([[self alloc] initWithHost:hostname]); +} + ++ (AWSKSReachability*) reachabilityToLocalNetwork +{ + struct sockaddr_in address; + bzero(&address, sizeof(address)); + address.sin_len = sizeof(address); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + + return aws_as_autorelease([[self alloc] initWithAddress:(const struct sockaddr*)&address]); +} + ++ (AWSKSReachability*) reachabilityToInternet +{ + struct sockaddr_in address; + bzero(&address, sizeof(address)); + address.sin_len = sizeof(address); + address.sin_family = AF_INET; + + return aws_as_autorelease([[self alloc] initWithAddress:(const struct sockaddr*)&address]); +} + +- (id) initWithHost:(NSString*) hostname +{ + hostname = [self extractHostName:hostname]; + const char* name = [hostname UTF8String]; + + struct sockaddr_in6 address; + bzero(&address, sizeof(address)); + address.sin6_len = sizeof(address); + address.sin6_family = AF_INET; + + if([hostname length] > 0) + { + if(inet_pton(address.sin6_family, name, &address.sin6_addr) != 1) + { + address.sin6_family = AF_INET6; + if(inet_pton(address.sin6_family, name, &address.sin6_addr) != 1) + { + return [self initWithReachabilityRef:SCNetworkReachabilityCreateWithName(NULL, name) + hostname:hostname]; + } + } + } + + return [self initWithAddress:(const struct sockaddr*)&address]; +} + +- (id) initWithAddress:(const struct sockaddr*) address +{ + return [self initWithReachabilityRef:SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, address) + hostname:nil]; +} + +- (id) initWithReachabilityRef:(SCNetworkReachabilityRef) reachabilityRef + hostname:(NSString*)hostname +{ + if((self = [super init])) + { + if(reachabilityRef == NULL) + { + NSLog(@"KSReachability Error: %s: Could not resolve reachability destination", __PRETTY_FUNCTION__); + goto init_failed; + } + else + { + self.hostname = hostname; + self.reachabilityRef = reachabilityRef; + + SCNetworkReachabilityContext context = {0, (aws_as_bridge void*)self, NULL, NULL, NULL}; + if(!SCNetworkReachabilitySetCallback(self.reachabilityRef, + onReachabilityChanged, + &context)) + { + NSLog(@"KSReachability Error: %s: SCNetworkReachabilitySetCallback failed", __PRETTY_FUNCTION__); + goto init_failed; + } + + if(!SCNetworkReachabilityScheduleWithRunLoop(self.reachabilityRef, + CFRunLoopGetMain(), + kCFRunLoopDefaultMode)) + { + NSLog(@"KSReachability Error: %s: SCNetworkReachabilityScheduleWithRunLoop failed", __PRETTY_FUNCTION__); + goto init_failed; + } + + // If you create a reachability ref using SCNetworkReachabilityCreateWithAddress(), + // it won't trigger from the runloop unless you kick it with SCNetworkReachabilityGetFlags() + if([hostname length] == 0) + { + SCNetworkReachabilityFlags flags; + // Note: This won't block because there's no host to look up. + if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + NSLog(@"KSReachability Error: %s: SCNetworkReachabilityGetFlags failed", __PRETTY_FUNCTION__); + goto init_failed; + } + + dispatch_async(dispatch_get_main_queue(), ^ + { + [self onReachabilityFlagsChanged:flags]; + }); + } + } + } + return self; + +init_failed: + aws_as_release(self); + self = nil; + return self; +} + +- (void) dealloc +{ + if(_reachabilityRef != NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, + CFRunLoopGetMain(), + kCFRunLoopDefaultMode); + CFRelease(_reachabilityRef); + } + aws_as_release(_hostname); + aws_as_release(_notificationName); + aws_as_release(_onReachabilityChanged); + aws_as_superdealloc(); +} + +- (NSString*) extractHostName:(NSString*) potentialURL +{ + if(potentialURL == nil) + { + return nil; + } + + NSString* host = [[NSURL URLWithString:potentialURL] host]; + if(host != nil) + { + return host; + } + return potentialURL; +} + +- (BOOL) isReachableWithFlags:(SCNetworkReachabilityFlags) flags +{ + if(!(flags & kSCNetworkReachabilityFlagsReachable)) + { + // Not reachable at all. + return NO; + } + + if(!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) + { + // Reachable with no connection required. + return YES; + } + + if((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | + kSCNetworkReachabilityFlagsConnectionOnTraffic)) && + !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) + { + // Automatic connection with no user intervention required. + return YES; + } + + return NO; +} + +- (BOOL) isReachableWWANOnlyWithFlags:(SCNetworkReachabilityFlags) flags +{ +#if TARGET_OS_IPHONE + BOOL isReachable = [self isReachableWithFlags:flags]; + BOOL isWWANOnly = (flags & kSCNetworkReachabilityFlagsIsWWAN) != 0; + return isReachable && isWWANOnly; +#else +#pragma unused(flags) + return NO; +#endif +} + +- (AWSKSReachabilityCallback) onInitializationComplete +{ + @synchronized(self) + { + return _onInitializationComplete; + } +} + +- (void) setOnInitializationComplete:(AWSKSReachabilityCallback) onInitializationComplete +{ + @synchronized(self) + { + aws_as_autorelease_noref(_onInitializationComplete); + _onInitializationComplete = [onInitializationComplete copy]; + if(_onInitializationComplete != nil && self.initialized) + { + dispatch_async(dispatch_get_main_queue(), ^ + { + [self callInitializationComplete]; + }); + } + } +} + +- (void) callInitializationComplete +{ + // This method expects to be called on the main run loop so that + // all callbacks occur on the main run loop. + @synchronized(self) + { + AWSKSReachabilityCallback callback = self.onInitializationComplete; + self.onInitializationComplete = nil; + if(callback != nil) + { + callback(self); + } + } +} + +- (void) onReachabilityFlagsChanged:(SCNetworkReachabilityFlags) flags +{ + // This method expects to be called on the main run loop so that + // all callbacks occur on the main run loop. + @synchronized(self) + { + BOOL wasInitialized = self.initialized; + + if(_flags != flags || !wasInitialized) + { + BOOL reachable = [self isReachableWithFlags:flags]; + BOOL WWANOnly = [self isReachableWWANOnlyWithFlags:flags]; + BOOL rChanged = (_reachable != reachable) || !wasInitialized; + BOOL wChanged = (_WWANOnly != WWANOnly) || !wasInitialized; + + [self willChangeValueForKey:kAWSKVOProperty_Flags]; + if(rChanged) [self willChangeValueForKey:kAWSKVOProperty_Reachable]; + if(wChanged) [self willChangeValueForKey:kAWSKVOProperty_WWANOnly]; + + _flags = flags; + _reachable = reachable; + _WWANOnly = WWANOnly; + + if(!wasInitialized) + { + self.initialized = YES; + } + + [self didChangeValueForKey:kAWSKVOProperty_Flags]; + if(rChanged) [self didChangeValueForKey:kAWSKVOProperty_Reachable]; + if(wChanged) [self didChangeValueForKey:kAWSKVOProperty_WWANOnly]; + + if(self.onReachabilityChanged != nil) + { + self.onReachabilityChanged(self); + } + + if(self.notificationName != nil) + { + NSNotificationCenter* nCenter = [NSNotificationCenter defaultCenter]; + [nCenter postNotificationName:self.notificationName object:self]; + } + + if(!wasInitialized) + { + [self callInitializationComplete]; + } + } + } +} + + +static void onReachabilityChanged(__unused SCNetworkReachabilityRef target, + SCNetworkReachabilityFlags flags, + void* info) +{ + AWSKSReachability* reachability = (aws_as_bridge AWSKSReachability*) info; + [reachability onReachabilityFlagsChanged:flags]; +} + +@end + + +// ---------------------------------------------------------------------- +#pragma mark - KSReachableOperation - +// ---------------------------------------------------------------------- + +@interface AWSKSReachableOperation () + +@property(nonatomic,readwrite,retain) AWSKSReachability* reachability; + +@end + + +@implementation AWSKSReachableOperation + +@synthesize reachability = _reachability; + ++ (AWSKSReachableOperation*) operationWithHost:(NSString*) host + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved +{ + return aws_as_autorelease([[self alloc] initWithHost:host + allowWWAN:allowWWAN + onReachabilityAchieved:onReachabilityAchieved]); +} + ++ (AWSKSReachableOperation*) operationWithReachability:(AWSKSReachability*) reachability + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved +{ + return aws_as_autorelease([[self alloc] initWithReachability:reachability + allowWWAN:allowWWAN + onReachabilityAchieved:onReachabilityAchieved]); +} + +- (id) initWithHost:(NSString*) host + allowWWAN:(BOOL) allowWWAN +onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved +{ + return [self initWithReachability:[AWSKSReachability reachabilityToHost:host] + allowWWAN:allowWWAN + onReachabilityAchieved:onReachabilityAchieved]; +} + +- (id) initWithReachability:(AWSKSReachability*) reachability + allowWWAN:(BOOL) allowWWAN + onReachabilityAchieved:(dispatch_block_t) onReachabilityAchieved +{ + if((self = [super init])) + { + self.reachability = reachability; + if(self.reachability == nil || onReachabilityAchieved == nil) + { + aws_as_release(self); + self = nil; + } + else + { + onReachabilityAchieved = aws_as_autorelease([onReachabilityAchieved copy]); + AWSKSReachabilityCallback onReachabilityChanged = ^(AWSKSReachability* reachability2) + { + @synchronized(reachability2) + { + if(reachability2.onReachabilityChanged != nil && + reachability2.reachable && + (allowWWAN || !reachability2.WWANOnly)) + { + reachability2.onReachabilityChanged = nil; + onReachabilityAchieved(); + } + } + }; + + self.reachability.onReachabilityChanged = onReachabilityChanged; + + // Check once manually in case the host is already reachable. + onReachabilityChanged(self.reachability); + } + } + return self; +} + +- (void) dealloc +{ + aws_as_release(_reachability); + aws_as_superdealloc(); +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSCocoaLumberjack.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSCocoaLumberjack.h new file mode 100644 index 00000000..69047725 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSCocoaLumberjack.h @@ -0,0 +1,87 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +/** + * Welcome to CocoaLumberjack! + * + * The project page has a wealth of documentation if you have any questions. + * https://github.com/CocoaLumberjack/CocoaLumberjack + * + * If you're new to the project you may wish to read "Getting Started" at: + * Documentation/GettingStarted.md + * + * Otherwise, here is a quick refresher. + * There are three steps to using the macros: + * + * Step 1: + * Import the header in your implementation or prefix file: + * + * #import + * + * Step 2: + * Define your logging level in your implementation file: + * + * // Log levels: off, error, warn, info, verbose + * static const AWSDDLogLevel ddLogLevel = AWSDDLogLevelVerbose; + * + * Step 2 [3rd party frameworks]: + * + * Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel: + * + * // #undef LOG_LEVEL_DEF // Undefine first only if needed + * #define LOG_LEVEL_DEF myLibLogLevel + * + * Define your logging level in your implementation file: + * + * // Log levels: off, error, warn, info, verbose + * static const AWSDDLogLevel myLibLogLevel = AWSDDLogLevelVerbose; + * + * Step 3: + * Replace your NSLog statements with AWSDDLog statements according to the severity of the message. + * + * NSLog(@"Fatal error, no dohickey found!"); -> AWSDDLogError(@"Fatal error, no dohickey found!"); + * + * AWSDDLog works exactly the same as NSLog. + * This means you can pass it multiple variables just like NSLog. + **/ + +#import + + +// Disable legacy macros +#ifndef AWSDD_LEGACY_MACROS + #define AWSDD_LEGACY_MACROS 0 +#endif + +// Core +#import "AWSDDLog.h" + +// Main macros +#import "AWSDDLogMacros.h" +#import "AWSDDAssertMacros.h" + +// Capture ASL +#import "AWSDDASLLogCapture.h" + +// Loggers +#import "AWSDDTTYLogger.h" +#import "AWSDDASLLogger.h" +#import "AWSDDFileLogger.h" +#import "AWSDDOSLogger.h" + +// CLI +#if __has_include("CLIColor.h") && TARGET_OS_OSX +#import "CLIColor.h" +#endif diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.h new file mode 100644 index 00000000..70825836 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.h @@ -0,0 +1,41 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import "AWSDDASLLogger.h" + +@protocol AWSDDLogger; + +/** + * This class provides the ability to capture the ASL (Apple System Logs) + */ +@interface AWSDDASLLogCapture : NSObject + +/** + * Start capturing logs + */ ++ (void)start; + +/** + * Stop capturing logs + */ ++ (void)stop; + +/** + * The current capture level. + * @note Default log level: AWSDDLogLevelVerbose (i.e. capture all ASL messages). + */ +@property (class) AWSDDLogLevel captureLevel; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.m b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.m new file mode 100644 index 00000000..36f3c5e8 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogCapture.m @@ -0,0 +1,230 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import "AWSDDASLLogCapture.h" + +// Disable legacy macros +#ifndef AWSDD_LEGACY_MACROS + #define AWSDD_LEGACY_MACROS 0 +#endif + +#import "AWSDDLog.h" + +#include +#include +#include +#include + +static BOOL _cancel = YES; +static AWSDDLogLevel _captureLevel = AWSDDLogLevelVerbose; + +#ifdef __IPHONE_8_0 + #define AWSDDASL_IOS_PIVOT_VERSION __IPHONE_8_0 +#endif +#ifdef __MAC_10_10 + #define AWSDDASL_OSX_PIVOT_VERSION __MAC_10_10 +#endif + +@implementation AWSDDASLLogCapture + +static aslmsg (*dd_asl_next)(aslresponse obj); +static void (*dd_asl_release)(aslresponse obj); + ++ (void)initialize +{ + #if (defined(AWSDDASL_IOS_PIVOT_VERSION) && __IPHONE_OS_VERSION_MAX_ALLOWED >= AWSDDASL_IOS_PIVOT_VERSION) || (defined(AWSDDASL_OSX_PIVOT_VERSION) && __MAC_OS_X_VERSION_MAX_ALLOWED >= AWSDDASL_OSX_PIVOT_VERSION) + #if __IPHONE_OS_VERSION_MIN_REQUIRED < AWSDDASL_IOS_PIVOT_VERSION || __MAC_OS_X_VERSION_MIN_REQUIRED < AWSDDASL_OSX_PIVOT_VERSION + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + // Building on falsely advertised SDK, targeting deprecated API + dd_asl_next = &aslresponse_next; + dd_asl_release = &aslresponse_free; + #pragma GCC diagnostic pop + #else + // Building on lastest, correct SDK, targeting latest API + dd_asl_next = &asl_next; + dd_asl_release = &asl_release; + #endif + #else + // Building on old SDKs, targeting deprecated API + dd_asl_next = &aslresponse_next; + dd_asl_release = &aslresponse_free; + #endif +} + ++ (void)start { + // Ignore subsequent calls + if (!_cancel) { + return; + } + + _cancel = NO; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { + [self captureAslLogs]; + }); +} + ++ (void)stop { + _cancel = YES; +} + ++ (AWSDDLogLevel)captureLevel { + return _captureLevel; +} + ++ (void)setCaptureLevel:(AWSDDLogLevel)level { + _captureLevel = level; +} + +#pragma mark - Private methods + ++ (void)configureAslQuery:(aslmsg)query { + const char param[] = "7"; // ASL_LEVEL_DEBUG, which is everything. We'll rely on regular AWSDDlog log level to filter + + asl_set_query(query, ASL_KEY_LEVEL, param, ASL_QUERY_OP_LESS_EQUAL | ASL_QUERY_OP_NUMERIC); + + // Don't retrieve logs from our own AWSDDASLLogger + asl_set_query(query, kAWSDDASLKeyAWSDDLog, kAWSDDASLAWSDDLogValue, ASL_QUERY_OP_NOT_EQUAL); + +#if !TARGET_OS_IPHONE || TARGET_SIMULATOR + int processId = [[NSProcessInfo processInfo] processIdentifier]; + char pid[16]; + sprintf(pid, "%d", processId); + asl_set_query(query, ASL_KEY_PID, pid, ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_NUMERIC); +#endif +} + ++ (void)aslMessageReceived:(aslmsg)msg { + const char* messageCString = asl_get( msg, ASL_KEY_MSG ); + if ( messageCString == NULL ) + return; + + int flag; + BOOL async; + + const char* levelCString = asl_get(msg, ASL_KEY_LEVEL); + switch (levelCString? atoi(levelCString) : 0) { + // By default all NSLog's with a ASL_LEVEL_WARNING level + case ASL_LEVEL_EMERG : + case ASL_LEVEL_ALERT : + case ASL_LEVEL_CRIT : flag = AWSDDLogFlagError; async = NO; break; + case ASL_LEVEL_ERR : flag = AWSDDLogFlagWarning; async = YES; break; + case ASL_LEVEL_WARNING : flag = AWSDDLogFlagInfo; async = YES; break; + case ASL_LEVEL_NOTICE : flag = AWSDDLogFlagDebug; async = YES; break; + case ASL_LEVEL_INFO : + case ASL_LEVEL_DEBUG : + default : flag = AWSDDLogFlagVerbose; async = YES; break; + } + + if (!(_captureLevel & flag)) { + return; + } + + // NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding]; + NSString *message = @(messageCString); + + const char* secondsCString = asl_get( msg, ASL_KEY_TIME ); + const char* nanoCString = asl_get( msg, ASL_KEY_TIME_NSEC ); + NSTimeInterval seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970; + double nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0; + NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9); + + NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds]; + + AWSDDLogMessage *logMessage = [[AWSDDLogMessage alloc]initWithMessage:message + level:_captureLevel + flag:flag + context:0 + file:@"AWSDDASLLogCapture" + function:0 + line:0 + tag:nil + options:0 + timestamp:timeStamp]; + + [AWSDDLog log:async message:logMessage]; +} + ++ (void)captureAslLogs { + @autoreleasepool + { + /* + We use ASL_KEY_MSG_ID to see each message once, but there's no + obvious way to get the "next" ID. To bootstrap the process, we'll + search by timestamp until we've seen a message. + */ + + struct timeval timeval = { + .tv_sec = 0 + }; + gettimeofday(&timeval, NULL); + unsigned long long startTime = timeval.tv_sec; + __block unsigned long long lastSeenID = 0; + + /* + syslogd posts kNotifyASLDBUpdate (com.apple.system.logger.message) + through the notify API when it saves messages to the ASL database. + There is some coalescing - currently it is sent at most twice per + second - but there is no documented guarantee about this. In any + case, there may be multiple messages per notification. + + Notify notifications don't carry any payload, so we need to search + for the messages. + */ + int notifyToken = 0; // Can be used to unregister with notify_cancel(). + notify_register_dispatch(kNotifyASLDBUpdate, ¬ifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token) + { + // At least one message has been posted; build a search query. + @autoreleasepool + { + aslmsg query = asl_new(ASL_TYPE_QUERY); + char stringValue[64]; + + if (lastSeenID > 0) { + snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID); + asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC); + } else { + snprintf(stringValue, sizeof stringValue, "%llu", startTime); + asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC); + } + + [self configureAslQuery:query]; + + // Iterate over new messages. + aslmsg msg; + aslresponse response = asl_search(NULL, query); + + while ((msg = dd_asl_next(response))) + { + [self aslMessageReceived:msg]; + + // Keep track of which messages we've seen. + lastSeenID = atoll(asl_get(msg, ASL_KEY_MSG_ID)); + } + dd_asl_release(response); + asl_free(query); + + if (_cancel) { + notify_cancel(token); + return; + } + + } + }); + } +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.h new file mode 100644 index 00000000..757708da --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.h @@ -0,0 +1,58 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +// Disable legacy macros +#ifndef AWSDD_LEGACY_MACROS + #define AWSDD_LEGACY_MACROS 0 +#endif + +#import "AWSDDLog.h" + +// Custom key set on messages sent to ASL +extern const char* const kAWSDDASLKeyAWSDDLog; + +// Value set for kAWSDDASLKeyAWSDDLog +extern const char* const kAWSDDASLAWSDDLogValue; + +/** + * This class provides a logger for the Apple System Log facility. + * + * As described in the "Getting Started" page, + * the traditional NSLog() function directs its output to two places: + * + * - Apple System Log + * - StdErr (if stderr is a TTY) so log statements show up in Xcode console + * + * To duplicate NSLog() functionality you can simply add this logger and a tty logger. + * However, if you instead choose to use file logging (for faster performance), + * you may choose to use a file logger and a tty logger. + **/ +@interface AWSDDASLLogger : AWSDDAbstractLogger + +/** + * Singleton method + * + * @return the shared instance + */ +@property (class, readonly, strong) AWSDDASLLogger *sharedInstance; + +// Inherited from AWSDDAbstractLogger + +// - (id )logFormatter; +// - (void)setLogFormatter:(id )formatter; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.m b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.m new file mode 100644 index 00000000..02c7af6a --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDASLLogger.m @@ -0,0 +1,121 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import "AWSDDASLLogger.h" +#import + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +const char* const kAWSDDASLKeyAWSDDLog = "AWSDDLog"; + +const char* const kAWSDDASLAWSDDLogValue = "1"; + +static AWSDDASLLogger *sharedInstance; + +@interface AWSDDASLLogger () { + aslclient _client; +} + +@end + + +@implementation AWSDDASLLogger + ++ (instancetype)sharedInstance { + static dispatch_once_t AWSDDASLLoggerOnceToken; + + dispatch_once(&AWSDDASLLoggerOnceToken, ^{ + sharedInstance = [[[self class] alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init { + if (sharedInstance != nil) { + return nil; + } + + if ((self = [super init])) { + // A default asl client is provided for the main thread, + // but background threads need to create their own client. + + _client = asl_open(NULL, "com.apple.console", 0); + } + + return self; +} + +- (void)logMessage:(AWSDDLogMessage *)logMessage { + // Skip captured log messages + if ([logMessage->_fileName isEqualToString:@"AWSDDASLLogCapture"]) { + return; + } + + NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message; + + if (message) { + const char *msg = [message UTF8String]; + + size_t aslLogLevel; + switch (logMessage->_flag) { + // Note: By default ASL will filter anything above level 5 (Notice). + // So our mappings shouldn't go above that level. + case AWSDDLogFlagError : aslLogLevel = ASL_LEVEL_CRIT; break; + case AWSDDLogFlagWarning : aslLogLevel = ASL_LEVEL_ERR; break; + case AWSDDLogFlagInfo : aslLogLevel = ASL_LEVEL_WARNING; break; // Regular NSLog's level + case AWSDDLogFlagDebug : + case AWSDDLogFlagVerbose : + default : aslLogLevel = ASL_LEVEL_NOTICE; break; + } + + static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; + + // NSLog uses the current euid to set the ASL_KEY_READ_UID. + uid_t const readUID = geteuid(); + + char readUIDString[16]; +#ifndef NS_BLOCK_ASSERTIONS + size_t l = snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); +#else + snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); +#endif + + NSAssert(l < sizeof(readUIDString), + @"Formatted euid is too long."); + NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])), + @"Unhandled ASL log level."); + + aslmsg m = asl_new(ASL_TYPE_MSG); + if (m != NULL) { + if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 && + asl_set(m, ASL_KEY_MSG, msg) == 0 && + asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 && + asl_set(m, kAWSDDASLKeyAWSDDLog, kAWSDDASLAWSDDLogValue) == 0) { + asl_send(_client, m); + } + asl_free(m); + } + //TODO handle asl_* failures non-silently? + } +} + +- (NSString *)loggerName { + return @"cocoa.lumberjack.aslLogger"; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.h new file mode 100644 index 00000000..347a7c33 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.h @@ -0,0 +1,123 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +// Disable legacy macros +#ifndef AWSDD_LEGACY_MACROS + #define AWSDD_LEGACY_MACROS 0 +#endif + +#import "AWSDDLog.h" + +/** + * This class provides an abstract implementation of a database logger. + * + * That is, it provides the base implementation for a database logger to build atop of. + * All that is needed for a concrete database logger is to extend this class + * and override the methods in the implementation file that are prefixed with "db_". + **/ +@interface AWSDDAbstractDatabaseLogger : AWSDDAbstractLogger { + +@protected + NSUInteger _saveThreshold; + NSTimeInterval _saveInterval; + NSTimeInterval _maxAge; + NSTimeInterval _deleteInterval; + BOOL _deleteOnEverySave; + + BOOL _saveTimerSuspended; + NSUInteger _unsavedCount; + dispatch_time_t _unsavedTime; + dispatch_source_t _saveTimer; + dispatch_time_t _lastDeleteTime; + dispatch_source_t _deleteTimer; +} + +/** + * Specifies how often to save the data to disk. + * Since saving is an expensive operation (disk io) it is not done after every log statement. + * These properties allow you to configure how/when the logger saves to disk. + * + * A save is done when either (whichever happens first): + * + * - The number of unsaved log entries reaches saveThreshold + * - The amount of time since the oldest unsaved log entry was created reaches saveInterval + * + * You can optionally disable the saveThreshold by setting it to zero. + * If you disable the saveThreshold you are entirely dependent on the saveInterval. + * + * You can optionally disable the saveInterval by setting it to zero (or a negative value). + * If you disable the saveInterval you are entirely dependent on the saveThreshold. + * + * It's not wise to disable both saveThreshold and saveInterval. + * + * The default saveThreshold is 500. + * The default saveInterval is 60 seconds. + **/ +@property (assign, readwrite) NSUInteger saveThreshold; + +/** + * See the description for the `saveThreshold` property + */ +@property (assign, readwrite) NSTimeInterval saveInterval; + +/** + * It is likely you don't want the log entries to persist forever. + * Doing so would allow the database to grow infinitely large over time. + * + * The maxAge property provides a way to specify how old a log statement can get + * before it should get deleted from the database. + * + * The deleteInterval specifies how often to sweep for old log entries. + * Since deleting is an expensive operation (disk io) is is done on a fixed interval. + * + * An alternative to the deleteInterval is the deleteOnEverySave option. + * This specifies that old log entries should be deleted during every save operation. + * + * You can optionally disable the maxAge by setting it to zero (or a negative value). + * If you disable the maxAge then old log statements are not deleted. + * + * You can optionally disable the deleteInterval by setting it to zero (or a negative value). + * + * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted. + * + * It's not wise to enable both deleteInterval and deleteOnEverySave. + * + * The default maxAge is 7 days. + * The default deleteInterval is 5 minutes. + * The default deleteOnEverySave is NO. + **/ +@property (assign, readwrite) NSTimeInterval maxAge; + +/** + * See the description for the `maxAge` property + */ +@property (assign, readwrite) NSTimeInterval deleteInterval; + +/** + * See the description for the `maxAge` property + */ +@property (assign, readwrite) BOOL deleteOnEverySave; + +/** + * Forces a save of any pending log entries (flushes log entries to disk). + **/ +- (void)savePendingLogEntries; + +/** + * Removes any log entries that are older than maxAge. + **/ +- (void)deleteOldLogEntries; + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.m b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.m new file mode 100644 index 00000000..b8bf8f03 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAbstractDatabaseLogger.m @@ -0,0 +1,660 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import "AWSDDAbstractDatabaseLogger.h" +#import + + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +@interface AWSDDAbstractDatabaseLogger () + +- (void)destroySaveTimer; +- (void)destroyDeleteTimer; + +@end + +#pragma mark - + +@implementation AWSDDAbstractDatabaseLogger + +- (instancetype)init { + if ((self = [super init])) { + _saveThreshold = 500; + _saveInterval = 60; // 60 seconds + _maxAge = (60 * 60 * 24 * 7); // 7 days + _deleteInterval = (60 * 5); // 5 minutes + } + + return self; +} + +- (void)dealloc { + [self destroySaveTimer]; + [self destroyDeleteTimer]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Override Me +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)db_log:(AWSDDLogMessage *)logMessage { + // Override me and add your implementation. + // + // Return YES if an item was added to the buffer. + // Return NO if the logMessage was ignored. + + return NO; +} + +- (void)db_save { + // Override me and add your implementation. +} + +- (void)db_delete { + // Override me and add your implementation. +} + +- (void)db_saveAndDelete { + // Override me and add your implementation. +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Private API +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)performSaveAndSuspendSaveTimer { + if (_unsavedCount > 0) { + if (_deleteOnEverySave) { + [self db_saveAndDelete]; + } else { + [self db_save]; + } + } + + _unsavedCount = 0; + _unsavedTime = 0; + + if (_saveTimer && !_saveTimerSuspended) { + dispatch_suspend(_saveTimer); + _saveTimerSuspended = YES; + } +} + +- (void)performDelete { + if (_maxAge > 0.0) { + [self db_delete]; + + _lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Timers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)destroySaveTimer { + if (_saveTimer) { + dispatch_source_cancel(_saveTimer); + + if (_saveTimerSuspended) { + // Must resume a timer before releasing it (or it will crash) + dispatch_resume(_saveTimer); + _saveTimerSuspended = NO; + } + + #if !OS_OBJECT_USE_OBJC + dispatch_release(_saveTimer); + #endif + _saveTimer = NULL; + } +} + +- (void)updateAndResumeSaveTimer { + if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0.0)) { + uint64_t interval = (uint64_t)(_saveInterval * (NSTimeInterval) NSEC_PER_SEC); + dispatch_time_t startTime = dispatch_time(_unsavedTime, interval); + + dispatch_source_set_timer(_saveTimer, startTime, interval, 1ull * NSEC_PER_SEC); + + if (_saveTimerSuspended) { + dispatch_resume(_saveTimer); + _saveTimerSuspended = NO; + } + } +} + +- (void)createSuspendedSaveTimer { + if ((_saveTimer == NULL) && (_saveInterval > 0.0)) { + _saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue); + + dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool { + [self performSaveAndSuspendSaveTimer]; + } }); + + _saveTimerSuspended = YES; + } +} + +- (void)destroyDeleteTimer { + if (_deleteTimer) { + dispatch_source_cancel(_deleteTimer); + #if !OS_OBJECT_USE_OBJC + dispatch_release(_deleteTimer); + #endif + _deleteTimer = NULL; + } +} + +- (void)updateDeleteTimer { + if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) { + uint64_t interval = (uint64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC); + dispatch_time_t startTime; + + if (_lastDeleteTime > 0) { + startTime = dispatch_time(_lastDeleteTime, interval); + } else { + startTime = dispatch_time(DISPATCH_TIME_NOW, interval); + } + + dispatch_source_set_timer(_deleteTimer, startTime, interval, 1ull * NSEC_PER_SEC); + } +} + +- (void)createAndStartDeleteTimer { + if ((_deleteTimer == NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) { + _deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue); + + if (_deleteTimer != NULL) { + dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool { + [self performDelete]; + } }); + + [self updateDeleteTimer]; + + if (_deleteTimer != NULL) { + dispatch_resume(_deleteTimer); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Configuration +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSUInteger)saveThreshold { + // The design of this method is taken from the AWSDDAbstractLogger implementation. + // For extensive documentation please refer to the AWSDDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax."); + + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + + __block NSUInteger result; + + dispatch_sync(globalLoggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = _saveThreshold; + }); + }); + + return result; +} + +- (void)setSaveThreshold:(NSUInteger)threshold { + dispatch_block_t block = ^{ + @autoreleasepool { + if (_saveThreshold != threshold) { + _saveThreshold = threshold; + + // Since the saveThreshold has changed, + // we check to see if the current unsavedCount has surpassed the new threshold. + // + // If it has, we immediately save the log. + + if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) { + [self performSaveAndSuspendSaveTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the AWSDDAbstractLogger implementation. + // For documentation please refer to the AWSDDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + + dispatch_async(globalLoggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)saveInterval { + // The design of this method is taken from the AWSDDAbstractLogger implementation. + // For extensive documentation please refer to the AWSDDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax."); + + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + + __block NSTimeInterval result; + + dispatch_sync(globalLoggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = _saveInterval; + }); + }); + + return result; +} + +- (void)setSaveInterval:(NSTimeInterval)interval { + dispatch_block_t block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* saveInterval != interval */ islessgreater(_saveInterval, interval)) { + _saveInterval = interval; + + // There are several cases we need to handle here. + // + // 1. If the saveInterval was previously enabled and it just got disabled, + // then we need to stop the saveTimer. (And we might as well release it.) + // + // 2. If the saveInterval was previously disabled and it just got enabled, + // then we need to setup the saveTimer. (Plus we might need to do an immediate save.) + // + // 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date. + // + // 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date. + // (Plus we might need to do an immediate save.) + + if (_saveInterval > 0.0) { + if (_saveTimer == NULL) { + // Handles #2 + // + // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self createSuspendedSaveTimer]; + [self updateAndResumeSaveTimer]; + } else { + // Handles #3 + // Handles #4 + // + // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self updateAndResumeSaveTimer]; + } + } else if (_saveTimer) { + // Handles #1 + + [self destroySaveTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the AWSDDAbstractLogger implementation. + // For documentation please refer to the AWSDDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + + dispatch_async(globalLoggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)maxAge { + // The design of this method is taken from the AWSDDAbstractLogger implementation. + // For extensive documentation please refer to the AWSDDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax."); + + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + + __block NSTimeInterval result; + + dispatch_sync(globalLoggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = _maxAge; + }); + }); + + return result; +} + +- (void)setMaxAge:(NSTimeInterval)interval { + dispatch_block_t block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* maxAge != interval */ islessgreater(_maxAge, interval)) { + NSTimeInterval oldMaxAge = _maxAge; + NSTimeInterval newMaxAge = interval; + + _maxAge = interval; + + // There are several cases we need to handle here. + // + // 1. If the maxAge was previously enabled and it just got disabled, + // then we need to stop the deleteTimer. (And we might as well release it.) + // + // 2. If the maxAge was previously disabled and it just got enabled, + // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) + // + // 3. If the maxAge was increased, + // then we don't need to do anything. + // + // 4. If the maxAge was decreased, + // then we should do an immediate delete. + + BOOL shouldDeleteNow = NO; + + if (oldMaxAge > 0.0) { + if (newMaxAge <= 0.0) { + // Handles #1 + + [self destroyDeleteTimer]; + } else if (oldMaxAge > newMaxAge) { + // Handles #4 + shouldDeleteNow = YES; + } + } else if (newMaxAge > 0.0) { + // Handles #2 + shouldDeleteNow = YES; + } + + if (shouldDeleteNow) { + [self performDelete]; + + if (_deleteTimer) { + [self updateDeleteTimer]; + } else { + [self createAndStartDeleteTimer]; + } + } + } + } + }; + + // The design of the setter logic below is taken from the AWSDDAbstractLogger implementation. + // For documentation please refer to the AWSDDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + + dispatch_async(globalLoggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)deleteInterval { + // The design of this method is taken from the AWSDDAbstractLogger implementation. + // For extensive documentation please refer to the AWSDDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax."); + + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + + __block NSTimeInterval result; + + dispatch_sync(globalLoggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = _deleteInterval; + }); + }); + + return result; +} + +- (void)setDeleteInterval:(NSTimeInterval)interval { + dispatch_block_t block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* deleteInterval != interval */ islessgreater(_deleteInterval, interval)) { + _deleteInterval = interval; + + // There are several cases we need to handle here. + // + // 1. If the deleteInterval was previously enabled and it just got disabled, + // then we need to stop the deleteTimer. (And we might as well release it.) + // + // 2. If the deleteInterval was previously disabled and it just got enabled, + // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) + // + // 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date. + // + // 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date. + // (Plus we might need to do an immediate delete.) + + if (_deleteInterval > 0.0) { + if (_deleteTimer == NULL) { + // Handles #2 + // + // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, + // if a delete is needed the timer will fire immediately. + + [self createAndStartDeleteTimer]; + } else { + // Handles #3 + // Handles #4 + // + // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self updateDeleteTimer]; + } + } else if (_deleteTimer) { + // Handles #1 + + [self destroyDeleteTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the AWSDDAbstractLogger implementation. + // For documentation please refer to the AWSDDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + + dispatch_async(globalLoggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (BOOL)deleteOnEverySave { + // The design of this method is taken from the AWSDDAbstractLogger implementation. + // For extensive documentation please refer to the AWSDDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax."); + + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + + __block BOOL result; + + dispatch_sync(globalLoggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = _deleteOnEverySave; + }); + }); + + return result; +} + +- (void)setDeleteOnEverySave:(BOOL)flag { + dispatch_block_t block = ^{ + _deleteOnEverySave = flag; + }; + + // The design of the setter logic below is taken from the AWSDDAbstractLogger implementation. + // For documentation please refer to the AWSDDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_queue_t globalLoggingQueue = [AWSDDLog loggingQueue]; + NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + + dispatch_async(globalLoggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Public API +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)savePendingLogEntries { + dispatch_block_t block = ^{ + @autoreleasepool { + [self performSaveAndSuspendSaveTimer]; + } + }; + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_async(self.loggerQueue, block); + } +} + +- (void)deleteOldLogEntries { + dispatch_block_t block = ^{ + @autoreleasepool { + [self performDelete]; + } + }; + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_async(self.loggerQueue, block); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark AWSDDLogger +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)didAddLogger { + // If you override me be sure to invoke [super didAddLogger]; + + [self createSuspendedSaveTimer]; + + [self createAndStartDeleteTimer]; +} + +- (void)willRemoveLogger { + // If you override me be sure to invoke [super willRemoveLogger]; + + [self performSaveAndSuspendSaveTimer]; + + [self destroySaveTimer]; + [self destroyDeleteTimer]; +} + +- (void)logMessage:(AWSDDLogMessage *)logMessage { + if ([self db_log:logMessage]) { + BOOL firstUnsavedEntry = (++_unsavedCount == 1); + + if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) { + [self performSaveAndSuspendSaveTimer]; + } else if (firstUnsavedEntry) { + _unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0); + [self updateAndResumeSaveTimer]; + } + } +} + +- (void)flush { + // This method is invoked by AWSDDLog's flushLog method. + // + // It is called automatically when the application quits, + // or if the developer invokes AWSDDLog's flushLog method prior to crashing or something. + + [self performSaveAndSuspendSaveTimer]; +} + +@end diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAssertMacros.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAssertMacros.h new file mode 100644 index 00000000..e38cd75f --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDAssertMacros.h @@ -0,0 +1,26 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +/** + * NSAsset replacement that will output a log message even when assertions are disabled. + **/ +#define AWSDDAssert(condition, frmt, ...) \ + if (!(condition)) { \ + NSString *description = [NSString stringWithFormat:frmt, ## __VA_ARGS__]; \ + AWSDDLogError(@"%@", description); \ + NSAssert(NO, description); \ + } +#define AWSDDAssertCondition(condition) AWSDDAssert(condition, @"Condition not satisfied: %s", #condition) + diff --git a/ios/Pods/AWSCore/AWSCore/Logging/AWSDDFileLogger.h b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDFileLogger.h new file mode 100644 index 00000000..dbbe84a7 --- /dev/null +++ b/ios/Pods/AWSCore/AWSCore/Logging/AWSDDFileLogger.h @@ -0,0 +1,512 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2016, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +// Disable legacy macros +#ifndef AWSDD_LEGACY_MACROS + #define AWSDD_LEGACY_MACROS 0 +#endif + +#import "AWSDDLog.h" + +@class AWSDDLogFileInfo; + +/** + * This class provides a logger to write log statements to a file. + **/ + + +// Default configuration and safety/sanity values. +// +// maximumFileSize -> kAWSDDDefaultLogMaxFileSize +// rollingFrequency -> kAWSDDDefaultLogRollingFrequency +// maximumNumberOfLogFiles -> kAWSDDDefaultLogMaxNumLogFiles +// logFilesDiskQuota -> kAWSDDDefaultLogFilesDiskQuota +// +// You should carefully consider the proper configuration values for your application. + +extern unsigned long long const kAWSDDDefaultLogMaxFileSize; +extern NSTimeInterval const kAWSDDDefaultLogRollingFrequency; +extern NSUInteger const kAWSDDDefaultLogMaxNumLogFiles; +extern unsigned long long const kAWSDDDefaultLogFilesDiskQuota; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * The LogFileManager protocol is designed to allow you to control all aspects of your log files. + * + * The primary purpose of this is to allow you to do something with the log files after they have been rolled. + * Perhaps you want to compress them to save disk space. + * Perhaps you want to upload them to an FTP server. + * Perhaps you want to run some analytics on the file. + * + * A default LogFileManager is, of course, provided. + * The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property. + * + * This protocol provides various methods to fetch the list of log files. + * + * There are two variants: sorted and unsorted. + * If sorting is not necessary, the unsorted variant is obviously faster. + * The sorted variant will return an array sorted by when the log files were created, + * with the most recently created log file at index 0, and the oldest log file at the end of the array. + * + * You can fetch only the log file paths (full path including name), log file names (name only), + * or an array of `AWSDDLogFileInfo` objects. + * The `AWSDDLogFileInfo` class is documented below, and provides a handy wrapper that + * gives you easy access to various file attributes such as the creation date or the file size. + */ +@protocol AWSDDLogFileManager +@required + +// Public properties + +/** + * The maximum number of archived log files to keep on disk. + * For example, if this property is set to 3, + * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk. + * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted. + * + * You may optionally disable this option by setting it to zero. + **/ +@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles; + +/** + * The maximum space that logs can take. On rolling logfile all old logfiles that exceed logFilesDiskQuota will + * be deleted. + * + * You may optionally disable this option by setting it to zero. + **/ +@property (readwrite, assign, atomic) unsigned long long logFilesDiskQuota; + +// Public methods + +/** + * Returns the logs directory (path) + */ +@property (nonatomic, readonly, copy) NSString *logsDirectory; + +/** + * Returns an array of `NSString` objects, + * each of which is the filePath to an existing log file on disk. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFilePaths; + +/** + * Returns an array of `NSString` objects, + * each of which is the fileName of an existing log file on disk. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFileNames; + +/** + * Returns an array of `AWSDDLogFileInfo` objects, + * each representing an existing log file on disk, + * and containing important information about the log file such as it's modification date and size. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFileInfos; + +/** + * Just like the `unsortedLogFilePaths` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFilePaths; + +/** + * Just like the `unsortedLogFileNames` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFileNames; + +/** + * Just like the `unsortedLogFileInfos` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFileInfos; + +// Private methods (only to be used by AWSDDFileLogger) + +/** + * Generates a new unique log file path, and creates the corresponding log file. + **/ +- (NSString *)createNewLogFile; + +@optional + +// Notifications from AWSDDFileLogger + +/** + * Called when a log file was archieved + */ +- (void)didArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didArchiveLogFile(atPath:)); + +/** + * Called when the roll action was executed and the log was archieved + */ +- (void)didRollAndArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didRollAndArchiveLogFile(atPath:)); + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Default log file manager. + * + * All log files are placed inside the logsDirectory. + * If a specific logsDirectory isn't specified, the default directory is used. + * On Mac, this is in `~/Library/Logs/`. + * On iPhone, this is in `~/Library/Caches/Logs`. + * + * Log files are named `"