Hi developers im having some issue or misplaced tasks
so i had to develop a framework with some functions
this is my main FUNCTION where the issue began
func saveDataDevice(idPos: String, macAddress: String) {
// this first function obtains the MAIN token for further tasks == 'tokenForTransaction'
let value = FirstInitDevice.tokentransaccional(username: idPos)
//now i'd 2 seconds timer after tokentransaccional is launched
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
//after obtain tokenForTransaction i can do any WS, deviceInitWsCall gets call now it returns 'PosId'
//after finish the task so i'd save it for further fuctions
let value2 = FirstInitDevice.deviceInitWsCall(serialNumber: idPos)
let posidd = value2.PosId
let convert = String(posidd)
UserDefaults.standard.set(convert, forKey: "PosId")
//now i can do the third function using PosId parameter and obtain 'rsa'
//this is where the trouble shows for the first time, because the application hasn't finish the past task
//FirstInitDevice.deviceInitWsCall is not done yet that's why my if == "" just in case ill show the error immediately
let value3 = FirstInitDevice.getKeyWS(posId: value2.PosId)
LoginSingleton.shared.pos_id = value2.PosId
if value3.rsa == "" {
let alert = UIAlertController(title: "alert", message: "Cannot init KEYS", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.destructive, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else {
// if not continue
//decrypt rsa data
let rsaData = RSA().getRSAData(publicKeyHex: value3.rsa)
keysSingleton.shared.tk = rsaData.tk
//func 4 runs after decrypt is done BUT is not, because third function is not over yet
let value4 = FirstInitDevice.callInitDukptKeys(pos_id: value2.PosId, rsa: rsaData.rsa, check_value: rsaData.checkValue, crc32: rsaData.crc32)
//same IF just in case == ""
if value4.ksnString == ""{
let alert = UIAlertController(title: "Alert", message: "Cannot init KEYS", preferredStyle: UIAlertController.Style.alert)
let action = UIAlertAction(title: "OK", style: UIAlertAction.Style.destructive, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
} else{
keysSingleton.shared.ksn = value4.ksnString
keysSingleton.shared.new_key = value4.newKey
keysSingleton.shared.tk = value4.ksnString
self.doTransaction()
}
}
})
}
as you can see one functions leads to another and so and so, it doesn't work without getting the previous parameter
for some reason the applications saves the LAST obtained parameter INSTED the current one, this apply to any other function in the library
i have tried
1.- increasing the timer for
DispatchQueue.main.asyncAfter(deadline: .now() + 8.0, execute: {
2.- set for every function deadline 8s
3.- set DispatchGroup() .enter .leave to every function
but it didn't work, so the question leads to How can i handle URLSession.shared.dataTask after they finish properly
this are the functions on my library
FIRST FUNCTION tokentransaccional
public static func tokentransaccional(username: String){
let baseUrl = "http://bla bla"
let headers = [
"Authorization": "Basic bla bla"
]
let url = URL(string: "bla bla")!
var request = URLRequest(url: url)
request.allHTTPHeaderFields = headers
request.httpMethod = "POST"
request.timeoutInterval = 60
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let password = username+"bla bla"
let postString = "bla bla"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
// check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
let responseError = convertedJsonIntoDict["error"] as? String
let errorDescription = convertedJsonIntoDict["error_description"] as? String
if responseError?.count == nil {
let tokenAcceso = convertedJsonIntoDict["access_token"] as? String
LoginSingleton.shared.tokenForTransaction = tokenAcceso ?? ""
UserDefaults.standard.set(tokenAcceso, forKey: "AccessTokenLogin")
} else {
print("error")
}
}
}
catch let error as NSError {
print("catch let error")
print(error.localizedDescription)
}
}
task.resume()
}
second function deviceInitWsCall
public static func deviceInitWsCall(serialNumber: String) -> (PosId: Int, transaction_profile: String) {
let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
let headers = [
"Authorization": "bla bla"
]
let baseUrl = "bla bla"
let portBPC = "bla bla"
let deviceInitWsPoint = "bla bla"
let Url = String(format: "bla bla")
let serviceUrl = URL(string: Url)
let parameterDictionary = ["bla bla": serialNumber]
var request = URLRequest(url: serviceUrl!)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
request.httpBody = httpBody
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
print(convertedJsonIntoDict)
let response = convertedJsonIntoDict
let status = response["status"] as? Bool
if status == true {
UserDefaults.standard.set(response, forKey: "deviceInitDictionary")
let mainResponse = response["dataResponse"] as! NSDictionary
let getPosId = mainResponse["posId"] as! Int
UserDefaults.standard.set(getPosId, forKey: "getPosId")
let getQps = mainResponse["qps"] as! Bool
let getTransactionProfile = mainResponse["transactionProfile"] as! String
UserDefaults.standard.set(getTransactionProfile, forKey: "getTransactionProfile")
let dataContact = mainResponse["contact"] as! NSDictionary
let indicatorPartialCancellation = mainResponse["partialCancellation"] as? Bool
LoginSingleton.shared.qps = getQps
UserDefaults.standard.set(getQps, forKey: "getQps")
LoginSingleton.getInstance().pos_id = getPosId
dataPresentReatailPresent.shared.posId = getPosId
LoginSingleton.getInstance().qps = getQps
LoginSingleton.getInstance().transaction_profile = getTransactionProfile
LoginSingleton.getInstance().partialCancellation = indicatorPartialCancellation ?? false
}
else{
print("error")
}
}
} catch let error as NSError {
print("catch let error")
print(error.localizedDescription)
}
}.resume()
let PosId = UserDefaults.standard.integer(forKey: "getPosId")
let transaction_profile = UserDefaults.standard.string(forKey: "getTransactionProfile") ?? ""
return (PosId, transaction_profile)
}
third function getKeyWS
public static func getKeyWS(posId: Int) -> (rsa: String, rsa_id: Int) {
let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
let headers = [
"Authorization": "bla bla"
]
let baseUrl = "bla bla"
let portBPC = ":bla bla"
let deviceGetKeyUrl = "bla bla"
let Url = String(format: "bla bla")
let serviceUrl = URL(string: Url)
let parameterDictionary = ["bla bla": posId]
var request = URLRequest(url: serviceUrl!)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
request.httpBody = httpBody
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
// Print out dictionary
print(convertedJsonIntoDict)
let response = convertedJsonIntoDict
guard let MainDataResponse = response["dataResponse"] as? NSDictionary else { return }
let rsa_id = MainDataResponse["rsaId"] as? Int ?? 0
let rsa = MainDataResponse["rsa"] as? String ?? ""
UserDefaults.standard.set(rsa_id, forKey: "rsa_id")
UserDefaults.standard.set(rsa, forKey: "rsa")
}
} catch let error as NSError {
print("catch let error")
print(error.localizedDescription)
}
}.resume()
let rsa = UserDefaults.standard.string(forKey: "rsa") ?? ""
let rsa_id = UserDefaults.standard.integer(forKey: "rsa_id")
return (rsa, rsa_id)
}
fourth function callInitDukptKeys
public static func callInitDukptKeys(pos_id: Int, rsa: String, check_value: String , crc32: String) -> (newKey: String, ksnString: String, crc32: String, checkValue: String) {
let token = UserDefaults.standard.string(forKey: "AccessTokenLogin") ?? ""
let headers = [
"Authorization": "bla bla"
]
let baseUrl = "bla bla"
let portBPC = ":bla bla"
let deviceInitDukptKeysUrll = "bla bla"
let UUrl = String(format: "bla bla")
let serviceUrlll = URL(string: UUrl)
let parameterDictionary = ["bla bla": String(pos_id),
"bla bla": rsa,
"bla bla": check_value,
"bla bla": crc32]
var requests = URLRequest(url: serviceUrlll!)
requests.httpMethod = "POST"
requests.allHTTPHeaderFields = headers
requests.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
requests.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
let httpBody = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: [])
requests.httpBody = httpBody
_ = URLSession.shared.dataTask(with: requests) { data, response, error in
guard let data = data, error == nil else {
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
do {
if let DictConvert = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
// Print out dictionary
let response = DictConvert
let status = response["status"] as? Bool
if status == true {
let mainResponse = response["dataResponse"] as? NSDictionary
let getKey = mainResponse!["key"] as? String
let keyCheckValue = mainResponse!["keyCheckValue"] as? String
let keyCrc32 = mainResponse!["keyCrc32"] as? String
let ksn = mainResponse!["ksn"] as? String
print("valor getKey: \(getKey)")
print("valor ksn: \(ksn)")
print("valor keyCrc32: \(keyCrc32)")
print("valor keyCheckValue: \(keyCheckValue)")
UserDefaults.standard.set(getKey, forKey: "getKey")
UserDefaults.standard.set(ksn, forKey: "ksn")
UserDefaults.standard.set(keyCrc32, forKey: "keyCrc32")
UserDefaults.standard.set(keyCheckValue, forKey: "keyCheckValue")
} else {
print("error")
}
}
} catch let error as NSError {
print("catch let error")
print(error.localizedDescription)
}
}.resume()
let newKey = UserDefaults.standard.string(forKey: "getKey") ?? ""
let ksnString = UserDefaults.standard.string(forKey: "ksn") ?? ""
let crc32 = UserDefaults.standard.string(forKey: "keyCrc32") ?? ""
let checkValue = UserDefaults.standard.string(forKey: "keyCheckValue") ?? ""
return (newKey, ksnString, crc32, checkValue)
}