Auto-Renewable Subscription Wrong Time Response Sandbox Mode - ios

I was trying to do local receipt validation and doing testing at present.
But from apple receipt response, I was getting wrong time related response so it become difficult for me to test application at present.
Here is log information:
Here is source code that I used for receipt validation:
public void CheckIfSubscriptionIsActive(bool validateReceipt)
{
ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
IAppleConfiguration appleConfig = builder.Configure<IAppleConfiguration>();
bool isSubscriptionRunning = false;
if (!string.IsNullOrEmpty(appleConfig.appReceipt))
{
if (validateReceipt)
{
// local receipt verification
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts)
{
Debug.Log("# server date: " + GameManager.Instance.ServerDate + " expire date: " + productReceipt.subscriptionExpirationDate);
int result = DateTime.Compare(GameManager.Instance.ServerDate, productReceipt.subscriptionExpirationDate);
if (result <= 0)
{
isSubscriptionRunning = true;
Debug.Log(" === ==== === Subscription Running: curr date: " + GameManager.Instance.ServerDate + " expire date: " + productReceipt.subscriptionExpirationDate);
}
//Debug.Log("PRODUCTID: " + productReceipt.productID);
//Debug.Log("PURCHASE DATE: " + productReceipt.purchaseDate);
//Debug.Log("EXPIRATION DATE: " + productReceipt.subscriptionExpirationDate);
//Debug.Log("CANCELDATE DATE: " + productReceipt.cancellationDate);
}
if (isSubscriptionRunning)
SubscriptionActivated();
// hide loading...
showLoader = false;
Camera.main.SendMessage("ActivateLoadingDialog", false, SendMessageOptions.DontRequireReceiver);
}
else
{
// server side receipt vecification
appReceipt = appleConfig.appReceipt;
StartCoroutine(CheckSubscriptionStatusServerSideVerification());
}
}
}
Usually Weekly subscription has 3 mins time duration so if I am not getting exact time then how can I do proper testing!!
In above image, I have mention both times, my local time is 15:01:04 and apple receipt response time is 09:37:18.
Using local device receipt validation at present I can't able to test the work. so what way exist for me for testing??

Basically in above problem, I was getting major time difference in Apple receipt response but now I have concluded the solution for this.
local time is 15:01:04
apple receipt response time is 09:37:18
Main reason for this is GMT time difference.
I am living in India so we have 5:30 time difference running.
So in Apple receipt time, I require to add this GMT time difference to get exact time values and after this we can complete our rest coding.
I will post link here with my Unity Support discussion if anybody required that.

Related

How to apply deduplication for an array returned in Zapier Code output

I have a Zapier Code block that does fetch for JSON array and the preprocess this data. I cannot use Zapier Webhook with polling, because I need to process the data a bit.
Zapier Webhook offers deduplication feature, by having id parameter associated with the items returned in an array from the URL endpoint. How can I achieve the same for Zapier Code? Currently, my zap is trying to process and trigger on the same data twice. This leads to the error that Zapier tries to send out the same tweet twice, every time the Code is triggered.
Here is mock data returned by my Code:
output = [{id: 1, name: "foo"}, {id: 2, name: "bar"}]
Currently, without deduplication, I am getting this email and having my zap disabled:
Your Zap named XXX was just stopped. This happened because our systems detected this Zap posted a duplicate tweet, which is against Twitter's Terms Of Service.
You can use storage by Zapier to achieve this. the ideal flow will be :
Trigger
Storage by Zapier [Get Value (use storage key = lastItemId) ]
Code By Zapier (Filter array return only those record that has id greater than the lastItemId)
Storage By Zapier (Set Value) : update lastItemId with the last item processed by Code By Zapier step
You can also use StoreClient in place of the Storage By zapier, but always update a existing key lastItemId and compare id of the record with ```lastItemId`` and at the end update StoreCLient key (lastItemId)
Based on the answer from Kishor Patidar, here is my code. I am adding the example code, here is too some time to figure it out. Specifically, in my case, the items cannot be processed in the order of appearance (no running counter primary keys) and also there are some limitations how far in the future Zapier can schedule actions (you can delay only up to one month).
The store also has a limitation of 500 keys.
// We need store for deduplication
// https://zapier.com/help/create/code-webhooks/store-data-from-code-steps-with-storeclient
// https://www.uuidgenerator.net/
var store = StoreClient('xxx');
// Where do we get our JSON data
const url = "https://xxx";
// Call FB public backend to get scheduled battles
const resp = await fetch(url);
const data = await resp.json();
let processed = [];
for(let entry of data.entries) {
console.log("Processing entry", entry.id);
// Filter out events with a non-wanted prize type
if(entry.prizes[0].type != "mytype") {
continue;
}
// Zapier can only delay tweets for one month
// As the code fires every 30 minutes,
// we are only interested scheduling tweets that happen
// very soon
const when = Date.parse(entry.startDate);
const now = Date.now();
if(!when) {
throw new Error("startDate missing");
}
if(when > now + 24 * 3600 * 1000) {
// Milliseconds not going to happen for next 24h
console.log("Too soon to schedule", entry.id, entry.startDate, now);
continue;
} else {
console.log("Starting to schedule", entry.id, entry.startDate, now);
}
const key = "myprefix_" + entry.id;
// Do manual deduplication
// https://stackoverflow.com/questions/64893057/how-to-apply-deduplication-for-an-array-returned-in-zapier-code-output
const existing = await store.get(key);
if(existing) {
// Already processed
console.log("Entry already processed", entry.id);
continue;
}
// Calculate some parameters on entry based on nested arrays
// and such
entry.startTimeFormat = "HH:mm";
// Generate URL for the tweet
entry.signUpURL = `https://xxx/${entry.id}`;
processed.push(entry);
// Do not tweet this entry twice,
// by setting a marker flag for it in store
await store.set(key, "deduplicated");
}
output = processed;

How to prepare APN for production

Im trying to deploy my app with notifications but it's giving me the biggest headache in the world. All other questions ive seen with regards to this seem outdated.
I set up APNs to be sent from a nodeJS script that I have running. When running in my sandbox everything was working well. As soon as I sent my app to TestFlight, notifications stopped sending. My script is still Successfully sending to the Notification Id registered with my phone but im assuming its not the correct production Id. If anyone canhelp get me sending production notifications it would be greatly appreciated! Thank you
APN Server code
var options = {
token: {
key: "AuthKey_6V27D43P5R.p8",
keyId: "3Z6SEF7GE5",
teamId: "ASQJ3L7765"
},
production: true
};
var apnProvider = new apn.Provider(options);
function SendIOSNotification(token, message, sound, payload, badge){
var deviceToken = token; //phone notification id
var notification = new apn.Notification(); //prepare notif
notification.topic = 'com.GL.Greek-Life'; // Specify your iOS app's Bundle ID (accessible within the project editor)
notification.expiry = Math.floor(Date.now() / 1000) + 3600; // Set expiration to 1 hour from now (in case device is offline)
notification.badge = badge; //selected badge
notification.sound = sound; //sound is configurable
notification.alert = message; //supports emoticon codes
notification.payload = {id: payload}; // Send any extra payload data with the notification which will be accessible to your app in didReceiveRemoteNotification
apnProvider.send(notification, deviceToken).then(function(result) { //send actual notifcation
// Check the result for any failed devices
var subToken = token.substring(0, 6);
console.log("Succesfully sent message to ", subToken);
}).catch( function (error) {
console.log("Faled to send message to ", subToken);
})
}

iOS Push notifications failing on Azure app

i have a ASP.NET Web API hosted as app on Azure and one of the APIs is to send notifications to users on iOS.
i am facing a strange issue on Azure. Sometimes the push notifications work and randomly stop after. I am using PushSharp and not NotificationHub or anything.
the code basically loops over device tokens and makes calls to APNS.
this seems to work fine locally but fails on Azure.
any ideas what i am missing? the error just says multiple errors.
thanks in advance.
var broker = new ApnsServiceBroker(config);
broker.OnNotificationFailed += (notification, exception) =>
{
callback(new Result { status = "FAIL", message = exception.Message });
Console.WriteLine("failed");
};
broker.OnNotificationSucceeded += (notification) =>
{
callback(new Result { status = "Success", message = "" });
Console.WriteLine("pass");
};
broker.Start();
broker.QueueNotification(new ApnsNotification
{
DeviceToken = userDeviceToken,
Payload = JObject.Parse("{ \"aps\" : { \"alert\" : \"" + message + "\", \"sound\":\"default\", \"badge\":0 },\"notification\":" + json + " }")
});
broker.Stop();

ios Swift Program app to delete things from parse after x amount of time?

Im creating an ios app using parse and swift. I want a users post to delete itself after x amount of time from the server. Is it possible to do this ?
Similar to how snapchat stories disapear after 24 hours.
i was thinking within the app i would make posts only visible if they were posted withiin the alotted time frame. That stops people from seeing old posts. I understand that i would then need something called cloud code to delete the posts. is this correct and how would i go about doing that.?
you can query through, get the createdAt date of the parse object and compare it to the current time, then delete it if its overdue.
wherever the data is retrieved, if they are user posts, you can put the query wherever you load the user posts. Once any one person tries to load that data and it's too old, it will be deleted and no one will see it.
The best way is using Cloud Jobs.
Sometimes you want to execute long running functions, and you don’t
want to wait for the response. Cloud Jobs are just meant for that. read More [https://docs.parseplatform.org/cloudcode/guide/#cloud-jobs]
Example :
// REMOVE A MOMENT VIDEO AFTER 24 HOURS
Parse.Cloud.job("remove", function (request, status) {
var date = new Date();
var timeNow = date.getTime();
var intervalOfTime = 1*24*60*60*1000; // 24 hours in milliseconds
var timeThen = timeNow - intervalOfTime;
// Limit date
var queryDate = new Date();
queryDate.setTime(timeThen);
// Query Moments
var query = new Parse.Query("Moments");
// Query the Moments after 24 hours
query.lessThanOrEqualTo("createdAt", queryDate);
query.find({
success: function (results) {
console.log("Moments: " + results.length);
// Delete Moment
query.each(function (object, err) {
object.destroy({
success: function (object) {
console.log("Successfully deleted: " + object.objectId);
},
error: function (error) {
console.log("Error: " + error.code + " - " + error.message);
},useMasterKey: true
})
})
},
error: function (error) {
console.log("Error: " + error.code + " - " + error.message);
}
});
});

Timeout Notification for Asynchronous Request

I am sending SPARQL queries as asynchronous requests to a SPARQL endpoint, currently DBpedia using the dotNetRDF library. While simpler queries usually work, more complex queries sometimes result in timeouts.
I am looking for a way to handle the timeouts by capturing some event when they occur.
I am sending my queries by using one of the asynchronous QueryWithResultSet overloads of the SparqlRemoteEndpoint class.
As described for SparqlResultsCallback, the state object will be replaced with an AsyncError instance if the asynchronous request failed. This does indicate that there was a timeout, however it seems that it only does so 10 minutes after the request was sent. When my timeout is, for example, 30 seconds, I would like to know 30 seconds later whether the request was successful. (35 seconds are ok, too, but you get the idea.)
Here is a sample application that sends two requests, the first of which is very simple and likely to succeed within the timeout (here set to 120 seconds), while the second one is rather complex and may easily fail on DBpedia:
using System;
using System.Collections.Concurrent;
using VDS.RDF;
using VDS.RDF.Query;
public class TestTimeout
{
private static string FormatResults(SparqlResultSet results, object state)
{
var result = new System.Text.StringBuilder();
result.AppendLine(DateTime.Now.ToLongTimeString());
var asyncError = state as AsyncError;
if (asyncError != null) {
result.AppendLine(asyncError.State.ToString());
result.AppendLine(asyncError.Error.ToString());
} else {
result.AppendLine(state.ToString());
}
if (results == null) {
result.AppendLine("results == null");
} else {
result.AppendLine("results.Count == " + results.Count.ToString());
}
return result.ToString();
}
public static void Main(string[] args)
{
Console.WriteLine("Launched ...");
Console.WriteLine(DateTime.Now.ToLongTimeString());
var output = new BlockingCollection<string>();
var ep = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"));
ep.Timeout = 120;
Console.WriteLine("Server == " + ep.Uri.AbsoluteUri);
Console.WriteLine("HTTP Method == " + ep.HttpMode);
Console.WriteLine("Timeout == " + ep.Timeout.ToString());
string query = "SELECT DISTINCT ?a\n"
+ "WHERE {\n"
+ " ?a <http://www.w3.org/2000/01/rdf-schema#label> ?b.\n"
+ "}\n"
+ "LIMIT 10\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 1");
query = "SELECT DISTINCT ?v5 ?v8\n"
+ "WHERE {\n"
+ " {\n"
+ " SELECT DISTINCT ?v5\n"
+ " WHERE {\n"
+ " ?v6 ?v5 ?v7.\n"
+ " FILTER(regex(str(?v5), \"[/#]c[^/#]*$\", \"i\")).\n"
+ " }\n"
+ " OFFSET 0\n"
+ " LIMIT 20\n"
+ " }.\n"
+ " OPTIONAL {\n"
+ " ?v5 <http://www.w3.org/2000/01/rdf-schema#label> ?v8.\n"
+ " FILTER(lang(?v8) = \"en\").\n"
+ " }.\n"
+ "}\n"
+ "ORDER BY str(?v5)\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 2");
Console.WriteLine("Queries sent.");
Console.WriteLine(DateTime.Now.ToLongTimeString());
Console.WriteLine();
string result = output.Take();
Console.WriteLine(result);
result = output.Take();
Console.WriteLine(result);
Console.ReadLine();
}
}
When I run this, I reproducibly get an output like the following:
13:13:23
Server == http://dbpedia.org/sparql
HTTP Method == GET
Timeout == 120
Queries sent.
13:13:25
13:13:25
Query 1
results.Count == 10
13:23:25
Query 2
VDS.RDF.Query.RdfQueryException: A HTTP error occurred while making an asynchron
ous query, see inner exception for details ---> System.Net.WebException: Der Rem
oteserver hat einen Fehler zurückgegeben: (504) Gatewaytimeout.
bei System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
bei VDS.RDF.Query.SparqlRemoteEndpoint.<>c__DisplayClass13.<QueryWithResultSe
t>b__11(IAsyncResult innerResult)
--- Ende der internen Ausnahmestapelüberwachung ---
results == null
Obviously, the exact times will be different, but the crucial point is that the error message based on the second query is received approximately 10 minutes after the request was sent, nowhere near the 2 minutes set for the timeout.
Am I using dotNetRDF incorrectly here, or is it intentional that I have to run an additional timer to measure the timeout myself and react on my own unless any response has been received meanwhile?
No you are not using dotNetRDF incorrectly rather there appears to be a bug that the timeouts set on an endpoint don't get honoured when running queries asynchronously. This has been filed as CORE-393
By the way even with this bug fixed you won't necessarily get a hard timeout at the set timeout. Essentially the value you set for the Timeout property of the SparqlRemoteEndpoint instance that value is used to set the Timeout property of the .Net HttpWebRequest. The documentation for HttpWebRequest.Timeout states the following:
Gets or sets the time-out value in milliseconds for the GetResponse
and GetRequestStream methods.
So you could wait up to the time-out to make the connection to POST the query and then up to the time-out again to start receiving a response. Once you start receiving a response the timeout becomes irrelevant and is not respected by the code that processes the response.
Therefore if you want a hard timeout you are better off implementing it yourself, longer term this may be something we can add to dotNetRDF but this is more complex to implement that simply fixing the bug about the timeout not getting honoured for the HTTP request.

Resources