This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
+271
View File
@@ -0,0 +1,271 @@
//
// RBXEventReporter.h
// RobloxMobile
//
// Created by Kyler Mulherin on 6/11/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface RBXEventReporter : NSObject
@property (atomic, strong, nullable) NSString* mobileDeviceID;
//Dictionary Keys as Enums
typedef NS_ENUM(NSInteger, RBXAnalyticsActionType)
{
RBXAActionClose,
RBXAActionSubmit,
RBXAActionTypeCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsButtonName)
{
RBXAButtonYes,
RBXAButtonNo,
RBXAButtonLogin,
RBXAButtonSignup,
RBXAButtonSocialSignIn,
RBXAButtonAbout,
RBXAButtonSubmit,
RBXAButtonClose,
RBXAButtonPlayNow,
RBXAButtonSearchOpen,
RBXAButtonSearchClose,
RBXAButtonSearch,
RBXAButtonRobux,
RBXAButtonBuildersClub,
RBXAButtonPopUpOkay,
RBXAButtonPopUpCancel,
RBXAButtonMoreButton,
RBXAButtonSeeAll,
RBXAButtonMessage,
RBXAButtonFriendRequest,
RBXAButtonFollow,
RBXAButtonJoinInGame,
RBXAButtonBadge,
RBXAButtonReadMessage,
RBXAButtonRefresh,
RBXAButtonReply,
RBXAButtonArchive,
RBXAButtonConnect,
RBXAButtonDisconnect,
RBXAButtonNameCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsContextName)
{
RBXAContextAppLaunch,
RBXAContextAppEnterForeground,
RBXAContextProtocolLaunch,
RBXAContextLanding,
RBXAContextSignup,
RBXAContextLogin,
RBXAContextSocialLogin,
RBXAContextSocialSignup,
RBXAContextCaptcha,
RBXAContextSettings,
RBXAContextSettingsEmail,
RBXAContextSettingsPassword,
RBXAContextSettingsSocial,
RBXAContextSettingsSocialConnect,
RBXAContextSettingsSocialDisconnect,
RBXAContextLogout,
RBXAContextMain,
RBXAContextGames,
RBXAContextGamesSeeAll,
RBXAContextSearch,
RBXAContextSearchResults,
RBXAContextMessages,
RBXAContextMore,
RBXAContextPurchasingRobux,
RBXAContextPurchasingBC,
RBXAContextProfile,
RBXAContextDraftMessage,
RBXAContextHybrid,
RBXAContextNameCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsCustomData)
{
RBXACustomUsers,
RBXACustomGames,
RBXACustomCatalog,
RBXACustomTabHome,
RBXACustomTabGames,
RBXACustomTabFriends,
RBXACustomTabCatalog,
RBXACustomTabMessages,
RBXACustomTabMore,
RBXACustomTabProfile,
RBXACustomTabGroups,
RBXACustomTabTrade,
RBXACustomTabInventory,
RBXACustomTabCharacter,
RBXACustomTabForum,
RBXACustomTabBlog,
RBXACustomTabHelp,
RBXACustomTabSettings,
RBXACustomTabEvent,
RBXACustomSectionInbox,
RBXACustomSectionSent,
RBXACustomSectionArchive,
RBXACustomSectionNotifications,
RBXACustomDataCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsEventName)
{
RBXAEventAppLaunch,
RBXAEventScreenLoaded,
RBXAEventButtonClick,
RBXAEventFormFieldValidation,
RBXAEventFormInteraction,
RBXAEventOpenGameDetail,
RBXAEventError,
RBXAEventNameCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsErrorName)
{
RBXAErrorNoError,
RBXAErrorUnknownLoginException,
RBXAErrorNoConnection,
RBXAErrorTooShort,
RBXAErrorTooLong,
RBXAErrorEmailInvalid,
RBXAErrorMissingRequiredField,
RBXAErrorBirthdayInvalid,
RBXAErrorGenderInvalid,
RBXAErrorPasswordInvalid,
RBXAErrorPrivileged,
RBXAErrorTwoStepVerification,
RBXAErrorWindowClosed,
RBXAErrorPasswordMismatch,
RBXAErrorNoResponse,
RBXAErrorNoResponseSuggestion,
RBXAErrorEndpointReturnedError,
RBXAErrorUsernameNotAllowed,
RBXAErrorUsernameTaken,
RBXAErrorUsernameInvalidWeb,
RBXAErrorFloodcheck,
RBXAErrorValidationJSONException,
RBXAErrorJSONReadFailure,
RBXAErrorJSONParseFailure,
RBXAErrorIncorrectCaptcha,
RBXAErrorMiscWebErrors,
RBXAErrorBadResponse,
RBXAErrorCannotParseData,
RBXAErrorNotApproved,
//Reporting Web Errors Analytics
RBXAErrorHttpError400,
RBXAErrorHttpError403,
RBXAErrorHttpError404,
RBXAErrorHttpError500,
RBXAErrorUnsupportedEncoding,
RBXAErrorJSON,
RBXAErrorNoHTTPResponse,
RBXAErrorInvalidUsername,
RBXAErrorInvalidPassword,
RBXAErrorMissingField,
RBXAErrorFloodcheckSuccess,
RBXAErrorFloodcheckFailure,
RBXAErrorFloodcheckFailurePerUser,
RBXAErrorFloodcheckAccountCreate,
RBXAErrorAccountNotApproved,
RBXAErrorIncompleteJSON,
RBXAErrorMissingUserInfo,
RBXAErrorGigya,
RBXAErrorGigyaLogin,
RBXAErrorGigyaKeyMissing,
RBXAErrorPostLoginUnspecified,
RBXAErrorCaptcha,
RBXAErrorAlreadyAuthenticated,
RBXAErrorUnknownError,
RBXAErrorUnexpectedResponseCode,
RBXAErrorBadCookieTryAgain,
RBXAErrorNameCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsFieldName)
{
RBXAFieldEmail,
RBXAFieldUsername,
RBXAFieldPassword,
RBXAFieldPasswordVerify,
RBXAFieldGender,
RBXAFieldBirthday,
RBXAFieldCaptcha,
RBXAFieldNameCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsResult)
{
RBXAResultUnknown,
RBXAResultSuccess,
RBXAResultFailure,
RBXAResultCount
};
typedef NS_ENUM(NSInteger, RBXAnalyticsGameLocations)
{
RBXALocationProfile,
RBXALocationGames,
RBXALocationGamesSeeAll,
RBXALocationGameSearch,
RBXALocationCount
};
//Constructor
+(nonnull id) sharedInstance;
//Acessors
-(nonnull NSString *) nameForContext:(RBXAnalyticsContextName)contextType;
-(nonnull NSString *) nameForResult:(RBXAnalyticsResult)resultType;
-(nonnull NSString *) nameForError:(RBXAnalyticsErrorName)errorType;
//GENERIC EVENTS
-(void) reportAppLaunch:(RBXAnalyticsContextName)context;
-(void) reportAppClose:(RBXAnalyticsContextName)context;
-(void) reportScreenLoaded:(RBXAnalyticsContextName)context;
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context;
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context
withCustomData:(RBXAnalyticsCustomData)customData;
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context
withCustomDataString:(nonnull NSString*)customDataString;
-(void) reportTabButtonClick:(RBXAnalyticsCustomData)buttonName;
-(void) reportFormFieldValidation:(RBXAnalyticsFieldName)fieldName
withContext:(RBXAnalyticsContextName)context
withError:(RBXAnalyticsErrorName)error;
-(void) reportOpenGameDetailFromSort:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
inSort:(nonnull NSNumber*)sortID
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count;
-(void) reportOpenGameDetailOnProfile:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count;
-(void) reportOpenGameDetailFromSearch:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count;
-(void) reportError:(RBXAnalyticsErrorName)error
withContext:(RBXAnalyticsContextName)context
withDataString:(nonnull NSString*)data;
@end
@@ -0,0 +1,478 @@
//
// RBXEventReporter.m
// RobloxMobile
//
// Created by Kyler Mulherin on 6/11/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import "RBXEventReporter.h"
#import "RobloxInfo.h"
#import "RobloxData.h"
#import "Reachability.h"
#import "iOSSettingsService.h"
#import "RobloxWebUtility.h"
#import "RBXFunctions.h"
#import "SessionReporter.h"
#define PARAM_TARGET @"t"
#define PARAM_EVENT @"evt"
#define PARAM_CONTEXT @"ctx"
#define PARAM_LOCAL_TIME @"lt"
#define PARAM_BUTTON @"btn"
#define PARAM_FIELD @"field"
#define PARAM_ERROR @"error"
#define PARAM_ACTION_TYPE @"aType"
#define PARAM_RESULT @"result"
#define PARAM_CUSTOM @"cstm"
#define PARAM_MOBILE_DEVICE_ID @"mdid"
#define PARAM_SORT @"sort"
#define PARAM_PAGE @"pg"
#define PARAM_ITEMS_IN_SORT @"tis"
#define PARAM_PLACE_ID @"pid"
#define PARAM_APP_STORE_SOURCE @"appStoreSource"
#define REPORTS_FILE_NAME @"analytics.txt"
#define APP_STORE_SOURCE @"apple"
@implementation RBXEventReporter
{
NSMutableArray* _actionTypes;
NSMutableArray* _buttonNames;
NSMutableArray* _contextNames;
NSMutableArray* _customData;
NSMutableArray* _eventNames;
NSMutableArray* _errorNames;
NSMutableArray* _fieldNames;
NSMutableArray* _resultNames;
NSMutableArray* _gameLocationNames;
}
//Constructors
+(id) sharedInstance
{
static dispatch_once_t rbxAnalyticsPred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&rbxAnalyticsPred, ^{ // Need to use GCD for thread-safe allocation
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-(id) init
{
self = [super init];
if (self)
{
[self initArrays];
}
return self;
}
-(void) initArrays
{
//NOTE - it is important that all of these arrays match up to the enums
_actionTypes = [NSMutableArray arrayWithCapacity:RBXAActionTypeCount];
_actionTypes[RBXAActionClose] = @"close";
_actionTypes[RBXAActionSubmit] = @"submit";
_buttonNames = [NSMutableArray arrayWithCapacity:RBXAButtonNameCount];
_buttonNames[RBXAButtonYes] = @"yes";
_buttonNames[RBXAButtonNo] = @"no";
_buttonNames[RBXAButtonLogin] = @"login";
_buttonNames[RBXAButtonSignup] = @"signup";
_buttonNames[RBXAButtonSocialSignIn]= @"socialSignIn";
_buttonNames[RBXAButtonAbout] = @"about";
_buttonNames[RBXAButtonSubmit] = @"submit";
_buttonNames[RBXAButtonClose] = @"close";
_buttonNames[RBXAButtonPlayNow] = @"playNow";
_buttonNames[RBXAButtonSearchOpen] = @"searchOpen";
_buttonNames[RBXAButtonSearchClose] = @"searchClose";
_buttonNames[RBXAButtonSearch] = @"search";
_buttonNames[RBXAButtonRobux] = @"robux";
_buttonNames[RBXAButtonBuildersClub]= @"buildersClub";
_buttonNames[RBXAButtonPopUpOkay] = @"popUpOkay";
_buttonNames[RBXAButtonPopUpCancel] = @"popUpCancel";
_buttonNames[RBXAButtonMoreButton] = @"moreButton";
_buttonNames[RBXAButtonSeeAll] = @"seeAll";
_buttonNames[RBXAButtonMessage] = @"sendMessage";
_buttonNames[RBXAButtonFriendRequest]=@"sendFriendRequest";
_buttonNames[RBXAButtonFollow] = @"toggleFollowUser";
_buttonNames[RBXAButtonJoinInGame] = @"joinInGame";
_buttonNames[RBXAButtonBadge] = @"badge";
_buttonNames[RBXAButtonReadMessage] = @"readMessage";
_buttonNames[RBXAButtonRefresh] = @"refresh";
_buttonNames[RBXAButtonReply] = @"reply";
_buttonNames[RBXAButtonArchive] = @"archive";
_buttonNames[RBXAButtonConnect] = @"connect";
_buttonNames[RBXAButtonDisconnect] = @"disconnect";
_contextNames= [NSMutableArray arrayWithCapacity:RBXAContextNameCount];
_contextNames[RBXAContextAppLaunch] = @"appLaunch";
_contextNames[RBXAContextAppEnterForeground]= @"appEnterForeground";
_contextNames[RBXAContextProtocolLaunch]= @"protocolLaunch";
_contextNames[RBXAContextLanding] = @"landing";
_contextNames[RBXAContextSignup] = @"signup";
_contextNames[RBXAContextLogin] = @"login";
_contextNames[RBXAContextSocialLogin] = @"socialLogin";
_contextNames[RBXAContextSocialSignup] = @"socialSignup";
_contextNames[RBXAContextCaptcha] = @"captcha";
_contextNames[RBXAContextSettings] = @"settings";
_contextNames[RBXAContextSettingsEmail] = @"settingsEmail";
_contextNames[RBXAContextSettingsPassword]=@"settingsPassword";
_contextNames[RBXAContextSettingsSocial]= @"settingsSocial";
_contextNames[RBXAContextSettingsSocialConnect]= @"settingsSocialConnect"; //needed for analytics
_contextNames[RBXAContextSettingsSocialDisconnect]= @"settingsSocialDisconnect"; //needed for analytics, nothing more
_contextNames[RBXAContextLogout] = @"logout";
_contextNames[RBXAContextMain] = @"main";
_contextNames[RBXAContextGames] = @"games";
_contextNames[RBXAContextGamesSeeAll] = @"gamesSeeAll";
_contextNames[RBXAContextSearch] = @"search";
_contextNames[RBXAContextSearchResults] = @"searchResults";
_contextNames[RBXAContextMessages] = @"messages";
_contextNames[RBXAContextMore] = @"more";
_contextNames[RBXAContextPurchasingRobux]= @"purchasingRobux";
_contextNames[RBXAContextPurchasingBC] = @"purchasingBC";
_contextNames[RBXAContextProfile] = @"profile";
_contextNames[RBXAContextDraftMessage] = @"draftMessage";
_contextNames[RBXAContextHybrid] = @"rbhybrid";
_customData = [NSMutableArray arrayWithCapacity:RBXACustomDataCount];
_customData[RBXACustomUsers] = @"users";
_customData[RBXACustomGames] = @"games";
_customData[RBXACustomCatalog] = @"catalog";
_customData[RBXACustomTabHome] = @"tabHome";
_customData[RBXACustomTabGames] = @"tabGames";
_customData[RBXACustomTabFriends] = @"tabFriends";
_customData[RBXACustomTabCatalog] = @"tabCatalog";
_customData[RBXACustomTabMessages] = @"tabMessages";
_customData[RBXACustomTabMore] = @"tabMore";
_customData[RBXACustomTabProfile] = @"tabProfile";
_customData[RBXACustomTabGroups] = @"tabGroups";
_customData[RBXACustomTabTrade] = @"tabTrade";
_customData[RBXACustomTabInventory] = @"tabInventory";
_customData[RBXACustomTabCharacter] = @"tabCharacter";
_customData[RBXACustomTabForum] = @"tabForum";
_customData[RBXACustomTabBlog] = @"tabBlog";
_customData[RBXACustomTabHelp] = @"tabHelp";
_customData[RBXACustomTabSettings] = @"tabSettings";
_customData[RBXACustomTabEvent] = @"tabEvent";
_customData[RBXACustomSectionInbox] = @"inbox";
_customData[RBXACustomSectionSent] = @"sent";
_customData[RBXACustomSectionArchive]=@"archive";
_customData[RBXACustomSectionNotifications]=@"notifications";
_eventNames = [NSMutableArray arrayWithCapacity:RBXAEventNameCount];
_eventNames[RBXAEventAppLaunch] = @"appLaunch";
_eventNames[RBXAEventScreenLoaded] = @"screenLoaded";
_eventNames[RBXAEventButtonClick] = @"buttonClick";
_eventNames[RBXAEventFormFieldValidation] = @"formFieldValidation";
_eventNames[RBXAEventFormInteraction] = @"formInteraction";
_eventNames[RBXAEventOpenGameDetail] = @"gameDetailReferral";
_eventNames[RBXAEventError] = @"clientsideError";
_errorNames = [NSMutableArray arrayWithCapacity:RBXAErrorNameCount];
_errorNames[RBXAErrorNoError] = @"NoError";
_errorNames[RBXAErrorUnknownLoginException] = @"UnknownLoginException";
_errorNames[RBXAErrorNoConnection] = @"NoInternetConnection";
_errorNames[RBXAErrorTooShort] = @"TooShort";
_errorNames[RBXAErrorTooLong] = @"TooLong";
_errorNames[RBXAErrorEmailInvalid] = @"EmailInvalid";
_errorNames[RBXAErrorMissingRequiredField] = @"MissingRequiredField";
_errorNames[RBXAErrorBirthdayInvalid] = @"BirthdayInvalid";
_errorNames[RBXAErrorGenderInvalid] = @"GenderInvalid";
_errorNames[RBXAErrorPasswordInvalid] = @"PasswordInvalid";
_errorNames[RBXAErrorPrivileged] = @"Privileged";
_errorNames[RBXAErrorTwoStepVerification] = @"TwoStepVerification";
_errorNames[RBXAErrorWindowClosed] = @"WindowClosed";
_errorNames[RBXAErrorPasswordMismatch] = @"PasswordMismatch";
_errorNames[RBXAErrorNoResponse] = @"NoResponse";
_errorNames[RBXAErrorNoResponseSuggestion] = @"NoResponseSuggestion";
_errorNames[RBXAErrorEndpointReturnedError] = @"EndpointReturnedError";
_errorNames[RBXAErrorUsernameNotAllowed] = @"UsernameNotAllowed";
_errorNames[RBXAErrorUsernameTaken] = @"UsernameTake";
_errorNames[RBXAErrorUsernameInvalidWeb] = @"UsernameInvalidWeb";
_errorNames[RBXAErrorFloodcheck] = @"Floodcheck";
_errorNames[RBXAErrorValidationJSONException] = @"ValidationJSONException";
_errorNames[RBXAErrorJSONReadFailure] = @"JSONReadFailure";
_errorNames[RBXAErrorJSONParseFailure] = @"JSONParseFailure";
_errorNames[RBXAErrorIncorrectCaptcha] = @"IncorrectCaptcha";
_errorNames[RBXAErrorMiscWebErrors] = @"misc_web_errors";
_errorNames[RBXAErrorBadResponse] = @"BadResponse";
_errorNames[RBXAErrorCannotParseData] = @"CannotParseData";
_errorNames[RBXAErrorNotApproved] = @"NotApprovedOrBanned";
_errorNames[RBXAErrorHttpError400] = @"HttpError400";
_errorNames[RBXAErrorHttpError403] = @"HttpError403";
_errorNames[RBXAErrorHttpError404] = @"HttpError404";
_errorNames[RBXAErrorHttpError500] = @"HttpError500";
_errorNames[RBXAErrorUnsupportedEncoding] = @"FailureUnsupportedEncoding";
_errorNames[RBXAErrorJSON] = @"FailureJSON";
_errorNames[RBXAErrorNoHTTPResponse] = @"FailureNoResponse";
_errorNames[RBXAErrorInvalidUsername] = @"FailureInvalidUsername";
_errorNames[RBXAErrorInvalidPassword] = @"FailureInvalidPassword";
_errorNames[RBXAErrorMissingField] = @"FailureMissingField";
_errorNames[RBXAErrorFloodcheckSuccess] = @"FailureSuccessFloodcheck";
_errorNames[RBXAErrorFloodcheckFailure] = @"FailureFailedFloodcheck";
_errorNames[RBXAErrorFloodcheckFailurePerUser] = @"FailurePerUserFloodcheck";
_errorNames[RBXAErrorFloodcheckAccountCreate] = @"FailureAccountCreateFloodcheck";
_errorNames[RBXAErrorAccountNotApproved] = @"AccountNotApproved";
_errorNames[RBXAErrorIncompleteJSON] = @"FailureIncompleteJSON";
_errorNames[RBXAErrorMissingUserInfo] = @"MissingUserInfo";
_errorNames[RBXAErrorGigya] = @"FailureGigya";
_errorNames[RBXAErrorGigyaLogin] = @"FailureGigyaLogin";
_errorNames[RBXAErrorGigyaKeyMissing] = @"FailureGigyaKeyMissing";
_errorNames[RBXAErrorPostLoginUnspecified] = @"FailurePostLoginUnspecified";
_errorNames[RBXAErrorCaptcha] = @"FailureCaptcha";
_errorNames[RBXAErrorAlreadyAuthenticated] = @"AlreadyAuthenticated";
_errorNames[RBXAErrorUnknownError] = @"FailureUnknownError";
_errorNames[RBXAErrorUnexpectedResponseCode] = @"FailureUnexpectedResponseCode";
_errorNames[RBXAErrorBadCookieTryAgain] = @"FailureBadCookie";
_fieldNames = [NSMutableArray arrayWithCapacity:RBXAFieldNameCount];
_fieldNames[RBXAFieldEmail] = @"email";
_fieldNames[RBXAFieldUsername] = @"username";
_fieldNames[RBXAFieldPassword] = @"password";
_fieldNames[RBXAFieldPasswordVerify]= @"passwordVerify";
_fieldNames[RBXAFieldGender] = @"gender";
_fieldNames[RBXAFieldBirthday] = @"birthday";
_resultNames = [NSMutableArray arrayWithCapacity:RBXAResultCount];
_resultNames[RBXAResultUnknown] = @"unknown";
_resultNames[RBXAResultSuccess] = @"success";
_resultNames[RBXAResultFailure] = @"failure";
_gameLocationNames = [NSMutableArray arrayWithCapacity:RBXALocationCount];
_gameLocationNames[RBXALocationProfile] = @"Profile";
_gameLocationNames[RBXALocationGames] = @"Games";
_gameLocationNames[RBXALocationGamesSeeAll] = @"GamesSeeAll";
_gameLocationNames[RBXALocationGameSearch] = @"GameSearch";
}
-(void) initMobileDeviceId
{
_mobileDeviceID = [RobloxData browserTrackerId];
if ([RBXFunctions isEmpty:_mobileDeviceID])
[RobloxData initializeBrowserTrackerWithCompletion:^(bool success, NSString *browserTracker) {
if (success)
_mobileDeviceID = browserTracker;
}];
}
/////////////////////////////////////////////////////////////////////
// Accessors
-(NSString *) nameForContext:(RBXAnalyticsContextName)contextType
{
return _contextNames[contextType];
}
-(NSString *) nameForResult:(RBXAnalyticsResult)resultType
{
return _resultNames[resultType];
}
-(NSString *) nameForError:(RBXAnalyticsErrorName)errorType
{
return _errorNames[errorType];
}
/////////////////////////////////////////////////////////////////////
// Event Reporting
// - creates reports based on the user interactions within the app
// then enqueues them for the EventReporter to send them
-(NSString*) getLocalTime
{
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
return [dateFormatter stringFromDate:[NSDate date]];
}
-(void) reportEvent:(nonnull NSDictionary*)params
{
iOSSettingsService* iOSSettings = [[RobloxWebUtility sharedInstance] getCachediOSSettings];
bool analyticsEnabled = iOSSettings->GetValueEnableAnalyticsEventReporting();
if (!analyticsEnabled) { return; }
//due to a timing issue, make sure the time is recorded before dispatching to a background thread
NSString* timeOfRequest = [self getLocalTime];
[RBXFunctions dispatchOnBackgroundThread:^
{
//Make sure we have a device id, can't report events without it
if (!_mobileDeviceID)
{
[self initMobileDeviceId];
if (!_mobileDeviceID)
{
//NSLog(@"Could not initialize the mobile device id, cannot report event.");
return;
}
}
//format the parameters, build in the mobileDeviceId, target, and local time
NSString* paramsString = [NSString stringWithFormat:@"%@=%@&%@=%@&%@=%@&",
PARAM_TARGET, @"mobile",
PARAM_MOBILE_DEVICE_ID, _mobileDeviceID,
PARAM_LOCAL_TIME, timeOfRequest];
//loop through the provided parameters and build those into the string as well
for (NSString* key in params)
if (params[key] && ((NSString*)params[key]).length > 0)
paramsString = [NSString stringWithFormat:@"%@%@=%@&", paramsString, key, params[key]];
else
NSLog(@"Empty parameter for key : %@",key);
//remove the last ampersand from the formatted parameter string
paramsString = [paramsString substringToIndex:paramsString.length - 1];
//construct the url
NSString* host = [[RobloxInfo getWWWBaseUrl] substringFromIndex:[@"http://www." length]];
NSString* urlString = [NSString stringWithFormat:@"http://ecsv2.%@pe?%@",
host,
paramsString];
//send the request to the server
//NSLog(@"Reporting Event : %@", urlString);
[RobloxData reportEvent:urlString
withCompletion:nil];
}];
}
//App Life Cycle events
-(void) reportAppLaunch:(RBXAnalyticsContextName)context
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventAppLaunch],
PARAM_CONTEXT : _contextNames[context],
PARAM_APP_STORE_SOURCE : APP_STORE_SOURCE };
[self reportEvent:eventParams];
}
-(void) reportAppClose:(RBXAnalyticsContextName)context
{
//DO SOMETHING
}
//Screen loaded
-(void) reportScreenLoaded:(RBXAnalyticsContextName)context
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventScreenLoaded],
PARAM_CONTEXT : _contextNames[context] };
[self reportEvent:eventParams];
}
//Button clicks
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventButtonClick],
PARAM_CONTEXT : _contextNames[context],
PARAM_BUTTON : _buttonNames[buttonName] };
[self reportEvent:eventParams];
}
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context
withCustomData:(RBXAnalyticsCustomData)customData
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventButtonClick],
PARAM_CONTEXT : _contextNames[context],
PARAM_BUTTON : _buttonNames[buttonName],
PARAM_CUSTOM : _customData[customData] };
[self reportEvent:eventParams];
}
-(void) reportButtonClick:(RBXAnalyticsButtonName)buttonName
withContext:(RBXAnalyticsContextName)context
withCustomDataString:(nonnull NSString*)customDataString
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventButtonClick],
PARAM_CONTEXT : _contextNames[context],
PARAM_BUTTON : _buttonNames[buttonName],
PARAM_CUSTOM : customDataString };
[self reportEvent:eventParams];
}
-(void) reportTabButtonClick:(RBXAnalyticsCustomData)buttonName
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventButtonClick],
PARAM_CONTEXT : _contextNames[RBXAContextMain],
PARAM_BUTTON : _customData[buttonName] };
[self reportEvent:eventParams];
}
//Form interactions / validations
-(void) reportFormFieldValidation:(RBXAnalyticsFieldName)fieldName
withContext:(RBXAnalyticsContextName)context
withError:(RBXAnalyticsErrorName)error
{
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventFormFieldValidation],
PARAM_CONTEXT : _contextNames[context],
PARAM_FIELD : _fieldNames[fieldName],
PARAM_ERROR : _errorNames[error] };
[self reportEvent:eventParams];
}
//Open Game
-(void) reportOpenGameDetailFromSort:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
inSort:(nonnull NSNumber*)sortID
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count
{
NSString* context = [NSString stringWithFormat:@"gameSort_SortFilter%@_TimeFilter0_GenreFilter0_Position%@",sortID.stringValue, gameIndex.stringValue];
NSDictionary* eventParams= @{ PARAM_EVENT : _eventNames[RBXAEventOpenGameDetail],
PARAM_CONTEXT : context,
PARAM_PAGE : _gameLocationNames[page],
PARAM_PLACE_ID : placeID.stringValue,
PARAM_ITEMS_IN_SORT : count.stringValue };
[self reportEvent:eventParams];
}
-(void) reportOpenGameDetailOnProfile:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count
{
NSString* context = [NSString stringWithFormat:@"profile_Position%@", gameIndex.stringValue];
NSDictionary* eventParams= @{ PARAM_EVENT : _eventNames[RBXAEventOpenGameDetail],
PARAM_CONTEXT : context,
PARAM_PAGE : _gameLocationNames[page],
PARAM_PLACE_ID : placeID.stringValue,
PARAM_ITEMS_IN_SORT : count.stringValue };
[self reportEvent:eventParams];
}
-(void) reportOpenGameDetailFromSearch:(nonnull NSNumber*)placeID
fromPage:(RBXAnalyticsGameLocations)page
atIndex:(nonnull NSNumber*)gameIndex
totalItemsInSort:(nonnull NSNumber*)count
{
NSString* context = [NSString stringWithFormat:@"gamesearch_Position%@", gameIndex.stringValue];
NSDictionary* eventParams= @{ PARAM_EVENT : _eventNames[RBXAEventOpenGameDetail],
PARAM_CONTEXT : context,
PARAM_PAGE : _gameLocationNames[page],
PARAM_PLACE_ID : placeID.stringValue,
PARAM_ITEMS_IN_SORT : count.stringValue };
[self reportEvent:eventParams];
}
//Errors
-(void) reportError:(RBXAnalyticsErrorName)error
withContext:(RBXAnalyticsContextName)context
withDataString:(nonnull NSString*)data
{
//useful for reporting general errors in the system
NSDictionary* eventParams = @{ PARAM_EVENT : _eventNames[RBXAEventError],
PARAM_CONTEXT : _contextNames[context],
PARAM_ERROR : _errorNames[error],
PARAM_CUSTOM : data };
[self reportEvent:eventParams];
}
@end
@@ -0,0 +1,30 @@
//
// RBXNotificationService.h
// RobloxMobile
//
// Created by Kyler Mulherin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RobloxNotifications.h"
#import "RobloxData.h"
#import "UserInfo.h"
@interface RBXMessagesPollingService : NSObject
//constructors
+(id) sharedInstance;
-(id) init;
-(void) clean;
//properties
@property (readonly) bool requestCompleted;
@property (readonly) int totalMessages;
@property (readonly) int totalFriendRequests;
@property (readonly, strong) NSTimer* notificationTimer;
//service functions
-(void) beginPolling;
-(void) pausePolling;
@end
@@ -0,0 +1,159 @@
//
// RBXMessagesPollingService
// Periodically polls the server for user notifications
//
// Created by Kyler Mulherin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "RBXMessagesPollingService.h"
#import "LoginManager.h"
#import "FastLog.h"
#import "RobloxNotifications.h"
//------ Server Fast Flags ---------
FASTFLAGVARIABLE(NotificationPollingServiceEnabled, true);
FASTINTVARIABLE(NotificationPollingServiceInterval, 10);
@implementation RBXMessagesPollingService
+(id) sharedInstance
{
static dispatch_once_t rbxNotServObj = 0;
__strong static id _sharedObject = nil;
dispatch_once(&rbxNotServObj, ^{ // Need to use GCD for thread-safe allocation
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-(id) init
{
//counter
_totalMessages = 0;
_totalFriendRequests = 0;
_requestCompleted = YES;
//observers
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginPolling) name:RBX_NOTIFY_DID_LEAVE_GAME object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePolling) name:RBX_NOTIFY_GAME_JOINED object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decrementMessagesTotal) name:RBX_NOTIFY_READ_MESSAGE object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pulseNotification) name:RBX_NOTIFY_LOGIN_SUCCEEDED object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearTotalMessages) name:RBX_NOTIFY_LOGGED_OUT object:nil];
//since friend requests are handled on the web, there is no way to communicate natively that the total has decremented
return self;
}
-(void) clean
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self deactivateNotificationTimer];
}
//server flags
- (BOOL)isServiceEnabled
{
return FFlag::NotificationPollingServiceEnabled;
}
- (int)getPollingInterval
{
return FInt::NotificationPollingServiceInterval;
}
//service functions
-(void) beginPolling { [self toggleTimer:YES];}
-(void) pausePolling { [self toggleTimer:NO]; }
-(void) toggleTimer:(BOOL)isOn
{
//use fast flags to simply escape if this service is not enabled
if (! [self isServiceEnabled]) return;
//to ensure that the timer is started and stopped on the same thread, dispatch the command here
dispatch_async(dispatch_get_main_queue(), ^
{
_requestCompleted = YES;
if (isOn) [self activateNotificationTimer];
else [self deactivateNotificationTimer];
});
}
-(void) activateNotificationTimer
{
if (!_notificationTimer)
{
_notificationTimer = [NSTimer scheduledTimerWithTimeInterval:[self getPollingInterval]
target:self
selector:@selector(fetchNotificationsFromServer)
userInfo:nil
repeats:YES];
}
}
-(void) deactivateNotificationTimer
{
if (_notificationTimer)
[_notificationTimer invalidate];
_notificationTimer = nil;
}
//count and total functions
-(NSDictionary*) createNotification
{
return [NSDictionary dictionaryWithObjects:@[[NSNumber numberWithInt:_totalMessages],[NSNumber numberWithInt:_totalFriendRequests]]
forKeys:@[@"unreadMessages", @"friendRequests"]];
}
-(void) fetchNotificationsFromServer
{
//escape if the user is not logged into an account
if (![[UserInfo CurrentPlayer] userLoggedIn]) { return; }
//do not perform multiple requests, wait for one to complete before requesting another
if (!_requestCompleted) return;
_requestCompleted = NO;
[RobloxData fetchTotalNotificationsForUser:[UserInfo CurrentPlayer].userId WithCompletion:^(RBXNotifications* notifications)
{
_requestCompleted = YES;
if (notifications)
{
if (_totalMessages != notifications.unreadMessages)
{
_totalMessages = notifications.unreadMessages;
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_INBOX_UPDATED object:nil];
}
if (_totalFriendRequests != notifications.unansweredFriendRequests)
{
_totalFriendRequests = notifications.unansweredFriendRequests;
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_FRIEND_REQUESTS_UPDATED object:nil];
}
}
}];
}
-(void) decrementMessagesTotal
{
_totalMessages = (_totalMessages - 1 <= 0) ? 0 : _totalMessages - 1;
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_NEW_MESSAGES_TOTAL object:nil];
}
-(void) decrementFriendRequestsTotal
{
_totalFriendRequests = (_totalFriendRequests - 1 <= 0) ? 0 : _totalFriendRequests - 1;
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_NEW_FRIEND_REQUESTS_TOTAL object:nil];
}
-(void) clearTotalMessages
{
//the user has logged out, clear the counter and notify any listeners
_totalMessages = 0;
_totalFriendRequests = 0;
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_NEW_MESSAGES_TOTAL object:[self createNotification]];
}
-(void) pulseNotification
{
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_NEW_MESSAGES_TOTAL object:[self createNotification]];
[[NSNotificationCenter defaultCenter] postNotificationName:RBX_NOTIFY_NEW_FRIEND_REQUESTS_TOTAL object:[self createNotification]];
}
@end
+799
View File
@@ -0,0 +1,799 @@
//
// RobloxData.h
// NativeShell-iOS
//
// Created by alichtin on 4/25/14.
// Copyright (c) 2014 Roblox. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CGGeometry.h>
#define BROWSER_TRACKER_KEY @"BrowserTracker"
#define BROWSER_TRACKER_KEY_OLD @"ABTestBrowserTracker"
typedef NS_ENUM(NSInteger, RBXGameSortType)
{
// 2015.0904 ajain - IDs updated against the prod web site today
RBXGameSortTypeDefault = -999,
RBXGameSortTypeUnknown = 0,
RBXGameSortTypePopular = 1,
RBXGameSortTypeTopFavorite = 2,
RBXGameSortTypeFeatured = 3,
RBXGameSortTypeMyFavorite = 5,
RBXGameSortTypeMyRecent = 6,
RBXGameSortTypeTopEarning = 8,
RBXGameSortTypeTopPaid = 9,
RBXGameSortTypePurchased = 10,
RBXGameSortTypeTopRated = 11,
RBXGameSortTypeBuildersClub = 14,
RBXGameSortTypePersonalServer = 15,
RBXGameSortTypeRecommended = 16,
RBXGameSortTypeFriendActivity = 17
};
typedef NS_ENUM(NSUInteger, RBXLeaderboardsTarget)
{
RBXLeaderboardsTargetUser = 0,
RBXLeaderboardsTargetClan = 1
};
typedef NS_ENUM(NSUInteger, RBXLeaderboardsTimeFilter)
{
RBXLeaderboardsTimeFilterDay = 0,
RBXLeaderboardsTimeFilterWeek = 1,
RBXLeaderboardsTimeFilterMonth = 2,
RBXLeaderboardsTimeFilterAllTime = 3
};
typedef NS_ENUM(NSUInteger, RBXUserBadgeType)
{
RBXUserBadgeTypePlayer = 0,
RBXUserBadgeTypeRoblox = 1
};
typedef NS_ENUM(NSUInteger, RBXMessageType)
{
RBXMessageTypeInbox = 0,
RBXMessageTypeSent = 1,
RBXMessageTypeArchive = 3,
RBXMessageTypeAnnouncements = 4
};
typedef NS_ENUM(NSUInteger, RBXFriendType)
{
RBXFriendTypeAllFriends = 0,
RBXFriendTypeRegularFriend = 1,
RBXFriendTypeBestFriend = 2,
RBXFriendTypeFriendRequest = 3
};
typedef NS_ENUM(NSUInteger, RBXFriendshipStatus)
{
RBXFriendshipStatusNonFriends = 0,
RBXFriendshipStatusRequestSent = 1,
RBXFriendshipStatusRequestReceived = 2,
RBXFriendshipStatusFriends = 3,
RBXFriendshipStatusBestFriends = 4
};
typedef NS_ENUM(NSUInteger, RBXCurrencyType)
{
RBXCurrencyTypeRobux = 1,
RBXCurrencyTypeTickets = 2
};
typedef NS_ENUM(NSUInteger, RBXUserVote)
{
RBXUserVoteNoVote = 0,
RBXUserVotePositive = 1,
RBXUserVoteNegative = 2
};
typedef NS_ENUM(NSUInteger, RBXThumbnailType)
{
RBXThumbnailImage = 1,
RBXThumbnailVideo = 33
};
typedef NS_ENUM(NSUInteger, RBXLocationType)
{
RBXLocationMobileWebsite = 0,
RBXLocationIOS = 1,
RBXLocationPage = 2,
RBXLocationStudio = 3,
RBXLocationGame = 4
};
typedef NS_ENUM(NSInteger, SearchResultType)
{
SearchResultGames = 1,
SearchResultUsers = 2,
SearchResultCatalog = 3,
SearchResultGroups = 4
};
typedef NS_ENUM(NSInteger, ABTestSubjectType)
{
ABTestSubjectTypeUser = 1,
ABTestSubjectTypeBrowserTracker = 2
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface RBXGameAttribute : NSObject
@property (strong, nonatomic) NSString* title;
@end
@interface RBXGameSort : RBXGameAttribute
+(RBXGameSort*) GameSortWithJSON:(NSDictionary*)json;
+(RBXGameSort*) MyGamesSort;
+(RBXGameSort*) RecentlyPlayedGamesSort;
+(RBXGameSort*) FavoriteGamesSort;
+(RBXGameSort*) DefaultSort;
@property (strong, nonatomic) NSNumber* sortID;
@end
@interface RBXGameGenre : RBXGameAttribute
+(NSArray*) allGenres;
@property (strong, nonatomic) NSNumber* genreID;
@end
@interface RBXGameData : NSObject
@property(strong, nonatomic) NSString* title;
@property(strong, nonatomic) NSString* creatorName;
@property(strong, nonatomic) NSNumber* creatorID;
@property(strong, nonatomic) NSString* players;
@property(strong, nonatomic) NSString* placeID;
@property(strong, nonatomic) NSNumber* universeID;
@property(strong, nonatomic) NSString* dateCreated;
@property(strong, nonatomic) NSString* dateUpdated;
@property(strong, nonatomic) NSString* gameDescription;
@property(strong, nonatomic) NSString* thumbnailURL;
@property(nonatomic) BOOL thumbnailIsFinal;
@property(nonatomic) NSUInteger favorited;
@property(nonatomic) NSUInteger visited;
@property(nonatomic) NSUInteger maxPlayers;
@property(nonatomic) NSUInteger onlineCount;
@property(nonatomic) NSUInteger upVotes;
@property(nonatomic) NSUInteger downVotes;
@property(nonatomic) RBXUserVote userVote;
@property(nonatomic) NSUInteger productID;
@property(nonatomic) NSUInteger price;
@property(nonatomic) BOOL userOwns;
@property(nonatomic) BOOL userFavorited;
@property(strong, nonatomic) NSString* assetGenre;
+ (RBXGameData*) parseGameFromJSON:(NSDictionary*)jsonGame;
@end
@interface RBXLeaderboardEntry : NSObject
@property(nonatomic) NSUInteger rank;
@property(strong, nonatomic) NSString* displayRank;
@property(nonatomic) NSUInteger userID;
@property(strong, nonatomic) NSString* name;
@property(nonatomic) NSUInteger targetID;
@property(strong, nonatomic) NSString* clanName;
@property(nonatomic) NSUInteger points;
@property(strong, nonatomic) NSString* displayPoints;
@property(nonatomic) NSUInteger clanEmblemID;
@property(strong, nonatomic) NSString* userAvatarURL;
@property(nonatomic) BOOL userAvatarIsFinal;
@property(strong, nonatomic) NSString* clanAvatarURL;
@property(nonatomic) BOOL clanAvatarIsFinal;
+ (RBXLeaderboardEntry*) parseLeaderboardEntry:(NSDictionary*)jsonEntry;
@end
@interface RBXUserProfileInfo : NSObject
@property(strong, nonatomic) NSNumber* userID;
@property(strong, nonatomic) NSString* username;
@property(strong, nonatomic) NSString* avatarURL;
@property(nonatomic) BOOL avatarIsFinal;
@property(nonatomic) BOOL BC;
@property(nonatomic) BOOL TBC;
@property(nonatomic) BOOL OBC;
@property(nonatomic) NSUInteger robux;
@property(nonatomic) NSUInteger tickets;
@property(nonatomic) RBXFriendshipStatus friendshipStatus;
@property(nonatomic) BOOL isFollowing;
+(RBXUserProfileInfo*) UserProfileInfoWithJSON:(NSDictionary*)json;
@end
@interface RBXUserAccount : NSObject
@property (strong, nonatomic) NSString* userName;
@property (strong, nonatomic) NSString* email;
//@property (strong, nonatomic) NSNumber* ageBracket;
@property (strong, nonatomic) NSNumber* userId;
@property BOOL isEmailVerfied;
@property BOOL userAbove13;
+(RBXUserAccount*) UserAccountWithJSON:(NSDictionary*)json;
@end
@interface RBXUserAccountNotifications : NSObject
@property int total;
@property BOOL emailNotificationEnabled;
@property BOOL passwordNotificationEnabled;
+(RBXUserAccountNotifications*) UserAccountNotificationsWithJSON:(NSDictionary*)json;
@end
@interface RBXUserPresence : NSObject
@property (strong, nonatomic) NSString* gameID;
@property (nonatomic) BOOL isOnline;
@property (strong, nonatomic) NSString* lastOnlineTime;
@property (strong, nonatomic) NSString* lastOnlineLocation;
@property (nonatomic) NSUInteger* locationType;
@property (nonatomic) NSUInteger* placeID;
+(RBXUserPresence*) UserPresenceWithJSON:(NSDictionary*)json;
@end
@interface RBXUserSearchInfo : NSObject
@property (strong, nonatomic) NSString* avatarURL;
@property (nonatomic) BOOL avatarIsFinal;
@property (strong, nonatomic) NSNumber* userId;
@property (strong, nonatomic) NSString* userName;
@property (strong, nonatomic) NSString* blurb;
@property (strong, nonatomic) NSString* previousNames;
@property (nonatomic) BOOL isOnline;
@property (strong, nonatomic) NSString* lastLocation;
@property (strong, nonatomic) NSString* profilePageURL;
@property (strong, nonatomic) NSString* lastSeenDate;
+(RBXUserSearchInfo*) UserSearchInfoWithJSON:(NSDictionary*)json;
@end
@interface RBXFollower : NSObject
@property (strong, nonatomic) NSNumber* userId;
@property (strong, nonatomic) NSString* username;
@property (strong,nonatomic) NSString* avatarURL;
@property (nonatomic) BOOL avatarIsFinal;
@property (nonatomic) BOOL isOnline;
+(RBXFollower*) FollowerWithJSON:(NSDictionary*)json;
@end
@interface RBXFriendInfo : NSObject
@property(strong, nonatomic) NSNumber* userID;
@property(strong, nonatomic) NSString* username;
@property(strong, nonatomic) NSString* avatarURL;
@property(nonatomic) BOOL avatarIsFinal;
@property(nonatomic) NSUInteger invitationID;
@property(nonatomic) RBXFriendshipStatus friendshipStatus;
@property(nonatomic) BOOL isOnline;
+(RBXFriendInfo*) FriendInfoWithJSON:(NSDictionary*)json;
+(RBXFriendInfo*) FriendInfoFromFollower:(RBXFollower*)follower;
@end
@interface RBXBadgeInfo : NSObject
@property BOOL isImageURLFinal;
@property BOOL isOwned;
@property double badgeRarity;
@property(strong, nonatomic) NSString* badgeAssetId;
@property(strong, nonatomic) NSString* imageURL;
@property(strong, nonatomic) NSString* name;
@property(strong, nonatomic) NSString* badgeDescription;
@property(strong, nonatomic) NSString* badgeCreatorId;
@property(strong, nonatomic) NSString* badgeCreatedDate;
@property(strong, nonatomic) NSString* badgeUpdatedDate;
@property(strong, nonatomic) NSString* badgeRarityName;
@property(strong, nonatomic) NSString* badgeTotalAwardedYesterday;
@property(strong, nonatomic) NSString* badgeTotalAwardedEver;
+(RBXBadgeInfo*) parseGameBadgeFromJSON:(NSDictionary*)json;
@end
@interface RBXMessageInfo : NSObject
@property(strong, nonatomic) NSNumber* senderUserID;
@property(strong, nonatomic) NSString* senderUsername;
@property(strong, nonatomic) NSNumber* recipientUserID;
@property(strong, nonatomic) NSString* recipientUsername;
@property(nonatomic) NSUInteger messageID;
@property(strong, nonatomic) NSString* date;
@property(strong, nonatomic) NSString* subject;
@property(strong, nonatomic) NSString* body;
@property(strong, nonatomic) NSString* message;
@property(nonatomic) BOOL isRead;
+(RBXMessageInfo*) MessageWithJSON:(NSDictionary*)json;
+(NSMutableArray*) ArrayFromJSON:(NSDictionary*)json;
@end
@interface RBXGameGear : NSObject
@property(strong, nonatomic) NSNumber* productID;
@property(strong, nonatomic) NSNumber* assetID;
@property(strong, nonatomic) NSString* name;
@property(strong, nonatomic) NSString* gearDescription;
@property(nonatomic) NSUInteger priceInRobux;
@property(nonatomic) NSUInteger priceInTickets;
@property(strong, nonatomic) NSNumber* sellerID;
@property(strong, nonatomic) NSString* sellerName;
@property(nonatomic) NSUInteger favoriteCount;
@property(nonatomic) BOOL userFavorited;
@property(nonatomic) NSUInteger totalSales;
@property(nonatomic) BOOL userOwns;
@property(nonatomic) BOOL isRentable;
@property(strong, nonatomic) NSNumber* promotionID;
@property(nonatomic) BOOL isForSale;
@end
@interface RBXGamePass : NSObject
@property(strong, nonatomic) NSNumber* productID;
@property(strong, nonatomic) NSNumber* passID;
@property(strong, nonatomic) NSString* passName;
@property(strong, nonatomic) NSString* passDescription;
@property(nonatomic) NSUInteger totalSales;
@property(nonatomic) NSUInteger priceInRobux;
@property(nonatomic) NSUInteger priceInTickets;
@property(nonatomic) NSUInteger upVotes;
@property(nonatomic) NSUInteger downVotes;
@property(nonatomic) NSUInteger favoriteCount;
@property(nonatomic) BOOL userFavorited;
@property(nonatomic) RBXUserVote userVote;
@property(nonatomic) BOOL userOwns;
@end
@interface RBXThumbnail : NSObject
@property bool assetIsFinal;
@property NSUInteger assetTypeId;
@property(strong, nonatomic) NSString* assetId;
@property(strong, nonatomic) NSString* assetHash;
@property(strong, nonatomic) NSString* assetURL;
+(RBXThumbnail*) ThumbnailWithJson:(NSDictionary*)json;
@end
@interface RBXNotifications : NSObject
@property NSInteger unreadMessages;
@property NSInteger unansweredFriendRequests;
+(RBXNotifications*) NotificationsWithJson:(NSDictionary*)json;
@end
@interface RBXSponsoredEvent : NSObject
@property (strong, nonatomic) NSString* eventName;
@property (strong, nonatomic) NSString* eventTitle;
@property (strong, nonatomic) NSString* eventLogoURLString;
@property (strong, nonatomic) NSString* eventPageType;
@property (strong, nonatomic) NSString* eventPageURLExtension;
+(RBXSponsoredEvent*) SponsoredEventWithJson:(NSDictionary*)json;
+(NSMutableArray*) EventsWithJson:(NSArray*)jsonArray;
@end
@interface RBXABTest : NSObject <NSCoding>
@property (strong, nonatomic) NSString* experimentName;
@property (strong, nonatomic) NSString* status;
@property (strong, nonatomic) NSNumber* subjectTargetId;
@property int subjectType;
@property int variation;
@property (nonatomic, readonly) BOOL isLockedOn;
+(RBXABTest*) TestWithJSON:(NSDictionary *)json;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface RobloxData : NSObject
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Images API
//
/* fetchURLForAssetID: Retrieve a game image url once it is final
*/
+ (void) fetchURLForAssetID:(NSString*)placeID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler;
/* fetchThumbnailURLForGameID: Retrieve a square game image url once it is final
*/
+ (void) fetchThumbnailURLForGameID:(NSString*)assetID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler;
/* fetchAvatarURLForUserID: Retrieve a user avatar url once it is final
*/
+ (void) fetchAvatarURLForUserID:(NSUInteger)userID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Analytics Event Reporting
//
+ (void) initializeBrowserTrackerWithCompletion:(void(^)(bool success, NSString* browserTracker))handler;
+ (NSString*) browserTrackerId;
+ (void) setBrowserTrackerId:(NSString *)trackerId;
+ (void) reportEvent:(NSString*)event
withCompletion:(void(^)(bool success, NSError* err))completion;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AB TEST and Tutorial APIs
//
+ (NSDictionary*) fetchABTestEnrollments:(NSString*)experimentalData;
+ (NSDictionary*) enrollInABTests:(NSString*)experimentalData;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Force Upgrade
//
+ (void) checkForForceUpgrade:(NSString*)versionNumber
withCompletion:(void(^)(NSDictionary* response))handler;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sign Up and Log In APIs
//
/* checkIfValidUsername: asks the server if a provided username is acceptable
*/
+(void) oldCheckIfValidUsername:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler;
+(void) checkIfValidUsername:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler;
/* checkIfBlacklistedEmail: asks the server if a provided email is acceptable
*/
+(void) checkIfBlacklistedEmail:(NSString*)email
completion:(void(^)(BOOL isBlacklisted))handler;
/* recommendUsername: asks the server for an alternative name to an already taken username
*/
+(void) recommendUsername:(NSString*)usernameToTry
completion:(void(^)(BOOL success, NSString* newUsername))handler;
/* checkIfValidPassword: asks the server if a password is acceptable
*/
+(void) oldCheckIfValidPassword:(NSString*)password
username:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler;
+(void) checkIfValidPassword:(NSString*)password
username:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Games API
//
/* fetchDefaultSorts: Retrieves the selected sorts to display in the main page
*/
+ (void) fetchDefaultSorts:(NSUInteger)minimumGamesInSort
completion:(void(^)(NSArray* sorts)) handler;
/* fetchAllSorts: Retrieves the all the sorts
*/
+ (void) fetchAllSorts:(void(^)(NSArray* sorts)) completionHandler;
/* fetchGameList: Retrieves a list of games from the server
*/
+ (void) fetchGameListWithSortID:(NSNumber*)sortID
genreID:(NSNumber*)genreID
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler;
+ (void) fetchGameListWithSortID:(NSNumber*)sortID
genreID:(NSNumber*)genreID
playerID:(NSNumber*)playerID
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler;
/* fetchUserPlaces: Retrieves the user places
*/
+ (void) fetchUserPlaces:(NSNumber*)userID
startIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void(^)(NSArray* games)) completionHandler;
/* fetchThumbnailsForPlace: Retrieves an array of image URLs for a given game
*/
+ (void) fetchThumbnailsForPlace:(NSString*)placeID
withSize:(CGSize)size
completion:(void(^)(NSArray* thumbnails))handler;
/* fetchUserFavoriteGames: Retrieves the user favorite games
*/
+ (void) fetchUserFavoriteGames:(NSNumber*)userID
startIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void(^)(NSArray* games)) completionHandler;
/* fetchGameDetails: Retrieve full game details
*/
+ (void) fetchGameDetails:(NSString*)placeID
completion:(void(^)(RBXGameData* game))handler;
/* fetchGameGear: Retrieve game gear
*/
+ (void) fetchGameGear:(NSString*)placeID
startIndex:(NSUInteger)startIndex
maxRows:(NSUInteger)maxRows
completion:(void(^)(NSArray* gear))handler;
/* fetchGamePasses: Retrieve game passes
*/
+ (void) fetchGamePasses:(NSString*)placeID
startIndex:(NSUInteger)startIndex
maxRows:(NSUInteger)maxRows
completion:(void(^)(NSArray* passes))handler;
/* fetchGameBadges: Retrieve game badges
*/
+ (void) fetchGameBadges:(NSString*)placeID
completion:(void(^)(NSArray* badges))handler;
/* searchGames: Retrieves a list of games from the server
*/
+ (void) searchGames:(NSString*)keyword
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler;
/* searchUsers: Retrieves a list of users from the server
*/
+ (void) searchUsers:(NSString*)keyword
fromIndex:(NSUInteger)startIndex
numUsers:(NSUInteger)numUsers
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* users)) handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Leaderboards API
//
/* fetchUserLeaderboardInfo: Retrieve the leaderboard info the the current logged in user.
Returns null if there is no session active or there was an error in the request.
*/
+ (void) fetchUserLeaderboardInfo:(RBXLeaderboardsTarget)target
userID:(NSNumber*)currentUserID
distributorID:(NSNumber*)distributorID
timeFilter:(RBXLeaderboardsTimeFilter)time
avatarSize:(CGSize)avatarSize
completion:(void(^)(RBXLeaderboardEntry* userEntry))handler;
/* fetchLeaderboards: Retrieve leaderboards
*/
+ (void) fetchLeaderboardsFor:(RBXLeaderboardsTarget)target
timeFilter:(RBXLeaderboardsTimeFilter)time
distributorID:(NSNumber*)distributorID
startIndex:(NSUInteger)startIndex
numItems:(NSUInteger)numItems
lastEntry:(RBXLeaderboardEntry*)lastEntry
avatarSize:(CGSize)avatarSize
completion:(void(^)(NSArray* leaderboard))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Profile API
//
/* fetchMyProfileWithSize: Retrieve current user profile info
*/
+ (void) fetchMyProfileWithSize:(CGSize)avatarSize
completion:(void(^)(RBXUserProfileInfo* profile))handler;
/* fetchUserProfile: Retrieve a user profile info
*/
+ (void) fetchUserProfile:(NSNumber*)userID
avatarSize:(CGSize)avatarSize
completion:(void(^)(RBXUserProfileInfo* profile))handler;
/* fetchUserFriends
*/
+ (void) fetchUserFriends:(NSNumber*)userID
friendType:(RBXFriendType)friendType
startIndex:(NSUInteger)startIndex
numItems:(NSUInteger)numItems
avatarSize:(CGSize)avatarSize
completion:(void(^)(NSUInteger totalFriends, NSArray* friends))handler;
/* fetchUserBadges
*/
+ (void) fetchUserBadges:(RBXUserBadgeType)badgeType
forUser:(NSNumber*)userID
badgeSize:(CGSize)badgeSize
completion:(void(^)(NSArray* badges))handler;
/* acceptFriendRequest
*/
+ (void) acceptFriendRequest:(NSUInteger)invitationID
withTargetUserID:(NSUInteger)targetUserID
completion:(void(^)(BOOL success))handler;
/* declineFriendRequest
*/
+ (void) declineFriendRequest:(NSUInteger)invitationID
withTargetUserID:(NSUInteger)targetUserID
completion:(void(^)(BOOL success))handler;
/* sendFriendRequest
*/
+ (void) sendFriendRequest:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* request friendship - API Proxy alternative to sending a friendship request
*/
+ (void) requestFrienshipWithUserID:(NSNumber*)friendUserID
completion:(void(^)(BOOL success))handler;
/* removeFriend
*/
+ (void) removeFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* unfriend - API proxy equivalent to removeFriend
*/
+ (void) unfriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* makeBestFriend - DEPRECATED
*/
+ (void) makeBestFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* removeBestFriend - DEPRECATED
*/
+ (void) removeBestFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* followUser
*/
+ (void) followUser:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* unfollowUser
*/
+ (void) unfollowUser:(NSNumber*)userID
completion:(void(^)(BOOL success))handler;
/* fetch count of friends
*/
+ (void) fetchFriendCount:(NSNumber*)currentUserId
withCompletion:(void(^)(BOOL success, NSString* message, int count))handler;
/* fetch a user's followers
*/
+ (void) fetchFollowersForUser:(NSNumber*)userID
atPage:(int)userPage
avatarSize:(CGSize)avatarSize
withCompletion:(void(^)(bool success, NSArray* followers))handler;
/* fetch all the users that a user is following
*/
+ (void) fetchMyFollowingAtPage:(int)userPage
avatarSize:(CGSize)avatarSize
withCompletion:(void(^)(bool success, NSArray* following))handler;
/* changeUserPassword
*/
+ (void) changeUserOldPassword:(NSString*)passwordOld
toNewPassword:(NSString*)passwordNew
withConfirmation:(NSString*)passwordConfirm
andCompletion:(void(^)(BOOL success, NSString* message))handler;
/* changeUserEmail
*/
+ (void) changeUserEmail:(NSString*)email
withPassword:(NSString*)password
andCompletion:(void(^)(BOOL success, NSString* message))handler;
/* fetch My Account
*/
+ (void) fetchMyAccountWithCompletion:(void(^)(RBXUserAccount* account))handler;
/* fetch User Has Set Password
*/
+ (void) fetchUserHasSetPasswordWithCompletion:(void(^)(bool passwordSet))handler;
/* fetch My Account Notifications
*/
+ (void) fetchAccountNotificationsWithCompletion:(void(^)(RBXUserAccountNotifications* notifications))handler;
/* fetch User Presence
*/
+ (void) fetchPresenceForUser:(NSNumber*)userID
withCompletion:(void(^)(RBXUserPresence*))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Messages API
//
/* fetchMessages: Retrieve user messages for the specified message type
*/
+ (void) fetchMessages:(RBXMessageType)messageType
pageNumber:(NSUInteger)pageNumber
pageSize:(NSUInteger)pageSize
completion:(void(^)(NSArray* messages))handler;
/* fetchNotificationsWithCompletion: Retrieve user notifications
*/
+ (void) fetchNotificationsWithCompletion:(void(^)(NSArray* messages))handler;
/* markMessageAsRead: Mark the specified message as read
*/
+ (void) markMessageAsRead:(NSUInteger)messageID completion:(void(^)(BOOL success))handler;
/* fetchTotalNotificationsForUser: WithCompletion: Retrieve a count of unread messages, and outstanding friend requests
* userID : the UserInfo playerID of the player to retrieve to retrieve the notifications for
* handler : an asynchronous callback block in which the retreived total notifications are returned
*/
+ (void) fetchTotalNotificationsForUser:(NSNumber*)userID WithCompletion:(void(^)(RBXNotifications* notifications))handler;
/* sendMessage: Send o reply a message to another user
*/
+ (void) sendMessage:(NSString*)body
subject:(NSString*)subject
recipientID:(NSNumber*)recipientID
replyMessageID:(NSNumber*)replyMessageID
completion:(void(^)(BOOL success, NSString* errorMessage))handler;
/* archiveMessage: Sends a message to the archived folder
*/
+ (void) archiveMessage:(NSUInteger)messageID
completion:(void(^)(BOOL success))handler;
/* unarchiveMessage: Removes a message from the archived folder
*/
+ (void) unarchiveMessage:(NSUInteger)messageID
completion:(void(^)(BOOL success))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// More Page API
//
+ (void) fetchSponsoredEvents:(void(^)(NSArray* events))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Store API
//
/* purchaseProduct: Purchase any product by its product ID
*/
+ (void) purchaseProduct:(NSUInteger)productID
currencyType:(RBXCurrencyType)currencyType
purchasePrice:(NSUInteger)purchasePrice
completion:(void(^)(BOOL success, NSString* errorMessage))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// General API
//
/* voteForAssetID: Vote for item
*/
+ (void) voteForAssetID:(NSString*)assetID
votePositive:(BOOL)votePositive
completion:(void(^)(BOOL success, NSString* message, NSUInteger totalPositives, NSUInteger totalNegatives, RBXUserVote userVote))handler;
/* favoriteToggleForAssetID: Toggle favorite for item
*/
+ (void) favoriteToggleForAssetID:(NSString*)assetID
completion:(void(^)(BOOL success, NSString* message))handler;
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,19 @@
//
// RobloxXSRFRequest.h
// RobloxMobile
//
// Created by Ariel Lichtin on 6/25/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "AFHTTPRequestOperationManager.h"
@interface RobloxXSRFRequest : AFHTTPRequestOperationManager
/* XSRF Protection: Post a message that modifies the state of the server using the safety ROBLOX token */
- (AFHTTPRequestOperation *)XSRFPOST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
@end
@@ -0,0 +1,68 @@
//
// RobloxXSRFRequest.m
// RobloxMobile
//
// Created by Ariel Lichtin on 6/25/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "RobloxXSRFRequest.h"
#import "RobloxInfo.h"
#define XSRF_HEADER_NAME @"X-CSRF-TOKEN"
// This cached token will be valid for this only user/session for a short time frame
// TODO: Put this token behind a mutex
NSString* cachedXSRFToken;
@implementation RobloxXSRFRequest
/* XSRF Protection: Post a message that modifies the state of the server using a safety ROBLOX token */
- (AFHTTPRequestOperation *)XSRFPOST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
//set the default useragent
[self.requestSerializer setValue:[RobloxInfo getUserAgentString] forHTTPHeaderField:@"User-Agent"];
// Set the cached ROBLOX token to the request
if(cachedXSRFToken)
{
[self.requestSerializer setValue:cachedXSRFToken forHTTPHeaderField:XSRF_HEADER_NAME];
}
AFHTTPRequestOperation* operation =
[self POST:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
// Return with success
success(operation, responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// If the status code is 403 (XSRF Token Validation Failed),
// the request should be reposted with the new token provided in the response
if(operation.response.statusCode == 403)
{
// Save the new token
NSDictionary* headerFields = operation.response.allHeaderFields;
cachedXSRFToken = headerFields[XSRF_HEADER_NAME];
// Start the request again
if (cachedXSRFToken)
[self XSRFPOST:URLString parameters:parameters success:success failure:failure];
else
failure(operation, error);
}
else
{
// The failure is for some other reason
// Return with error
failure(operation, error);
}
}];
return operation;
}
@end