public void postAction(string actionId, IDictionary actionProperties, string objectId, IDictionary objectProperties, string objectInstanceId = null, CarrotRequestResponse callback = null) { if(string.IsNullOrEmpty(objectId)) { throw new ArgumentNullException("objectId must not be null or empty string.", "objectId"); } if(string.IsNullOrEmpty(actionId)) { throw new ArgumentNullException("actionId must not be null or empty string.", "actionId"); } if(objectProperties == null) { throw new ArgumentNullException("objectProperties must not be null.", "objectProperties"); } else if(!objectProperties.Contains("title") || !objectProperties.Contains("description") || !objectProperties.Contains("image")) { throw new ArgumentException("objectProperties must contain keys for 'title', 'description', and 'image'.", "objectProperties"); } objectProperties["object_type"] = objectId; if(!string.IsNullOrEmpty(objectInstanceId)) objectProperties["object_instance_id"] = objectInstanceId; Dictionary<string, object> parameters = new Dictionary<string, object>() { {"action_id", actionId}, {"action_properties", actionProperties == null ? new Dictionary<string, object>() : actionProperties}, {"object_properties", objectProperties} }; StartCoroutine(cachedRequestCoroutine(ServiceType.Post, "/me/actions.json", parameters, callback)); }
private IEnumerator signedRequestCoroutine(Request carrotRequest, CarrotRequestResponse callback = null) { Response ret = Response.UnknownError; string errorText = null; string hostname = hostForServiceType(carrotRequest.ServiceType); if(string.IsNullOrEmpty(hostname)) { if(callback != null) callback(Response.OK, "", null); return false; } if(string.IsNullOrEmpty(mUserId)) { throw new NullReferenceException("UserId is empty. Assign a UserId before using Carrot."); } ServicePointManager.ServerCertificateValidationCallback = CarrotCertValidator; Dictionary<string, object> urlParams = new Dictionary<string, object> { {"api_key", mUserId}, {"game_id", mFacebookAppId}, {"request_date", carrotRequest.RequestDate}, {"request_id", carrotRequest.RequestId} }; Dictionary<string, object> parameters = carrotRequest.Parameters; // If this has an attached image, bytes will be placed here. byte[] imageBytes = null; if(parameters != null) { // Check for image on dynamic objects if(parameters.ContainsKey("object_properties")) { IDictionary objectProperties = parameters["object_properties"] as IDictionary; object image = objectProperties["image"]; Texture2D imageTex2D; if((imageTex2D = image as Texture2D) != null) { imageBytes = imageTex2D.EncodeToPNG(); using(SHA256 sha256 = SHA256Managed.Create()) { objectProperties["image_sha"] = System.Text.Encoding.UTF8.GetString(sha256.ComputeHash(imageBytes)); } } else if(image is string) { objectProperties["image_url"] = image; } objectProperties.Remove("image"); } // Merge params foreach(KeyValuePair<string, object> entry in parameters) { urlParams[entry.Key] = entry.Value; } } UnityEngine.WWWForm formPayload = new UnityEngine.WWWForm(); addCommonPayloadFields(formPayload, urlParams); string[] keys = new string[urlParams.Keys.Count]; urlParams.Keys.CopyTo(keys, 0); foreach(string key in keys) { string asStr; if((asStr = urlParams[key] as string) != null) { formPayload.AddField(key, asStr); } else { formPayload.AddField(key, Json.Serialize(urlParams[key])); } } string sig = signParams(hostname, carrotRequest.Endpoint, mCarrotAppSecret, urlParams); formPayload.AddField("sig", sig); // Attach image if(imageBytes != null) { formPayload.AddBinaryData("image_bytes", imageBytes); } UnityEngine.WWW request = new UnityEngine.WWW(String.Format("https://{0}{1}", hostname, carrotRequest.Endpoint), formPayload); yield return request; Dictionary<string, object> reply = null; int statusCode = 0; if(request.error != null) { Match match = Regex.Match(request.error, "^([0-9]+)"); if(match.Success) { statusCode = int.Parse(match.Value); } else { errorText = request.error; Debug.Log(request.error); } } else { if(!string.IsNullOrEmpty(request.text)) { reply = Json.Deserialize(request.text) as Dictionary<string, object>; statusCode = (int)((long)reply["code"]); } } switch(statusCode) { case 201: case 200: // Successful ret = Response.OK; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.Ready; break; case 401: // User has not authorized 'publish_actions', read only ret = Response.ReadOnly; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.ReadOnly; break; case 402: // Service tier exceeded, not posted ret = Response.UserLimitHit; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.Ready; break; case 403: // Authentication error, app secret incorrect ret = Response.BadAppSecret; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.Ready; break; case 404: // Resource not found ret = Response.NotFound; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.Ready; break; case 405: // User is not authorized for Facebook App ret = Response.NotAuthorized; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.NotAuthorized; break; case 424: // Dynamic OG object not created due to parameter error ret = Response.ParameterError; if(carrotRequest.ServiceType != ServiceType.Metrics) this.Status = AuthStatus.Ready; break; } if(callback != null) callback(ret, errorText, reply); }
private CarrotRequestResponse cachedRequestHandler(CarrotCache.CachedRequest cachedRequest, CarrotRequestResponse callback) { return (Response ret, string errorText, Dictionary<string, object> reply) => { switch(ret) { case Response.OK: case Response.NotFound: case Response.ParameterError: cachedRequest.RemoveFromCache(); break; default: cachedRequest.AddRetryInCache(); break; } if(callback != null) callback(ret, errorText, reply); }; }
private IEnumerator cachedRequestCoroutine(ServiceType serviceType, string endpoint, Dictionary<string, object> parameters, CarrotRequestResponse callback = null) { CarrotCache.CachedRequest cachedRequest = mCarrotCache.CacheRequest(serviceType, endpoint, parameters); if((int)serviceType <= (int)mAuthStatus) { yield return StartCoroutine(signedRequestCoroutine(cachedRequest, cachedRequestHandler(cachedRequest, callback))); } else { if(callback != null) callback(Response.OK, authStatusString(mAuthStatus), null); yield return null; } }
/// <summary> /// Inform Carrot about a purchase of premium currency for metrics tracking. /// </summary> /// <param name="amount">The amount of real money spent.</param> /// <param name="currency">The type of real money spent (eg. USD).</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postPremiumCurrencyPurchase(float amount, string currency, CarrotRequestResponse callback = null) { StartCoroutine(cachedRequestCoroutine(ServiceType.Metrics, "/purchase.json", new Dictionary<string, object>() { {"amount", amount}, {"currency", currency} }, callback)); }
/// <summary> /// Post a high score to Carrot. /// </summary> /// <param name="score">Score.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postHighScore(uint score, CarrotRequestResponse callback = null) { StartCoroutine(cachedRequestCoroutine(ServiceType.Post, "/me/scores.json", new Dictionary<string, object>() { {"value", score} }, callback)); }
/// <summary> /// Sends an Open Graph action which will create a new object. /// </summary> /// <param name="actionId">Carrot action id.</param> /// <param name="actionProperties">Parameters to be submitted with the action.</param> /// <param name="viralObject">A <see cref="ViralObject"/> describing the object to be created.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postAction(string actionId, IDictionary actionProperties, ViralObject viralObject, CarrotRequestResponse callback = null) { if(string.IsNullOrEmpty(actionId)) { throw new ArgumentNullException("actionId must not be null or empty string.", "actionId"); } if(viralObject == null) { throw new ArgumentNullException("viralObject must not be null.", "viralObject"); } Dictionary<string, object> parameters = new Dictionary<string, object>() { {"action_id", actionId}, {"action_properties", actionProperties == null ? new Dictionary<string, object>() : actionProperties}, {"object_properties", viralObject.toDictionary()} }; StartCoroutine(cachedRequestCoroutine(ServiceType.Post, "/me/actions.json", parameters, callback)); }
/// <summary> /// Sends an Open Graph action which will create a new object. /// </summary> /// <param name="actionId">Carrot action id.</param> /// <param name="viralObject">A <see cref="ViralObject"/> describing the object to be created.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postAction(string actionId, ViralObject viralObject, CarrotRequestResponse callback = null) { postAction(actionId, null, viralObject, callback); }
/// <summary> /// Sends an Open Graph action which will use an existing object. /// </summary> /// <param name="actionId">Carrot action id.</param> /// <param name="actionProperties">Parameters to be submitted with the action.</param> /// <param name="objectInstanceId">Carrot object instance id.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postAction(string actionId, IDictionary actionProperties, string objectInstanceId, CarrotRequestResponse callback = null) { if(string.IsNullOrEmpty(objectInstanceId)) { throw new ArgumentNullException("objectInstanceId must not be null or empty string.", "objectInstanceId"); } if(string.IsNullOrEmpty(actionId)) { throw new ArgumentNullException("actionId must not be null or empty string.", "actionId"); } Dictionary<string, object> parameters = new Dictionary<string, object>() { {"action_id", actionId}, {"action_properties", actionProperties == null ? new Dictionary<string, object>() : actionProperties}, {"object_properties", new Dictionary<string, object>()} }; if(objectInstanceId != null) parameters["object_instance_id"] = objectInstanceId; StartCoroutine(cachedRequestCoroutine(ServiceType.Post, "/me/actions.json", parameters, callback)); }
/// <summary> /// Sends an Open Graph action which will use an existing object. /// </summary> /// <param name="actionId">Carrot action id.</param> /// <param name="objectInstanceId">Carrot object instance id.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postAction(string actionId, string objectInstanceId, CarrotRequestResponse callback = null) { postAction(actionId, null, objectInstanceId, callback); }
/// <summary> /// Post an achievement to Carrot. /// </summary> /// <param name="achievementId">Carrot achievement id.</param> /// <param name="callback">Optional <see cref="CarrotRequestResponse"/> which will be used to deliver the reply.</param> public void postAchievement(string achievementId, CarrotRequestResponse callback = null) { if(string.IsNullOrEmpty(achievementId)) { throw new ArgumentNullException("achievementId must not be null or empty string.", "achievementId"); } StartCoroutine(cachedRequestCoroutine(ServiceType.Post, "/me/achievements.json", new Dictionary<string, object>() { {"achievement_id", achievementId} }, callback)); }
/// public void popupFeedPost(string objectInstanceId, Dictionary<string, object> objectProperties = null, CarrotRequestResponse callback = null) { if(string.IsNullOrEmpty(objectInstanceId)) { throw new ArgumentNullException("objectInstanceId must not be null or empty string.", "objectInstanceId"); } Dictionary<string, object> parameters = new Dictionary<string, object>() { {"object_instance_id", objectInstanceId}, {"object_properties", objectProperties == null ? new Dictionary<string, object>() : objectProperties} }; Request request = new Request(ServiceType.Post, "/me/feed_post.json", parameters); StartCoroutine(signedRequestCoroutine(request, (Response response, string errorText, Dictionary<string, object> reply) => { if(response == Response.OK) { Dictionary<string, object> fb_data = reply["fb_data"] as Dictionary<string, object>; if(fb_data["method"] as string == "feed") { if(mFacebookSDKType == FacebookSDKType.OfficialUnitySDK) { string actionName = ""; string actionLink = ""; if(fb_data.ContainsKey("actions")) { object[] actions = fb_data["actions"] as object[]; if(actions != null && actions.Length > 0) { // Will only ever have 1 element Dictionary<string, object> action = actions[0] as Dictionary<string, object>; actionName = action["name"] as string; actionLink = action["link"] as string; } } MethodInfo mi1 = typeof(Carrot).GetMethod("unitySDKFeedPostCallback", BindingFlags.NonPublic | BindingFlags.Instance); object fbDelegate = Delegate.CreateDelegate(mFacebookDelegateType, this, mi1); mOfficialFBSDKFeedMethod.Invoke(null, new object[] { "", // FBID of timeline this should be posted to (default: current) fb_data["link"] as string, "", // Name of the link (default: App Name) fb_data["caption"] as string, fb_data["description"] as string, fb_data["picture"] as string, "", // URL of audio/video content actionName, // Action name actionLink, // Action link fb_data["ref"] as string, new Dictionary<string, string[]>{}, fbDelegate }); } else if(mFacebookSDKType == FacebookSDKType.JavaScriptSDK) { Application.ExternalEval("FB.ui(" + Json.Serialize(fb_data) + ", function(response) {" + " if(response == null || response == undefined) { response = {canceled: true}; }" + " " + mUnityObject2Instance + ".getUnity().SendMessage('CarrotGameObject', 'javascriptSDKFeedPostCallback', JSON.stringify(response));" + "});" ); } } } else { // Something-something danger zone } })); }
public void postAction(string actionId, string objectId, IDictionary objectProperties, string objectInstanceId = null, CarrotRequestResponse callback = null) { postAction(actionId, null, objectId, objectProperties, objectInstanceId, callback); }