How to emit an custom event in socket.io? - swift

this is the first time I work with socket. I'm creating a chat feature that connect from my app to the server. I tried a couple ways but nothing works. I connect my app with socket/ Websocket successfully but I emit but not getting return data from server.
let SocketURL:String = "https://apps.abc.com:8080"
let WSSSocketURL:String = "wss://apps.abc.com:8080"
var conversationID:Int = 0
var socket:SocketIOClient?
var socketManager:SocketManager?
var otherChatUser:ChatUser = ChatUser()
var messageList:[ChatMessage] = [ChatMessage]()
var NumberOfSection:Int = 2
func setupSocket() -> Void {
socketManager = SocketManager(socketURL: URL(string: SocketURL)!, config: [.log(true), .compress])
self.socket = socketManager?.defaultSocket
socketManager?.config = SocketIOClientConfiguration(
arrayLiteral: .connectParams(["token": KeychainService.getWssToken() as Any, "EIO" : 3]),
.path("/wss"))
self.socket!.connect()
self.socket?.on(clientEvent: .connect) {
data, ack in
self.con_create()
}
}
func con_create() -> Void {
self.socketManager?.engine?.ws?.connect()
self.socketManager?.engine?.ws?.onConnect = {
let JsonData = [ "user" : self.otherChatUser.AuthID ]
self.socket?.emit("con_create", JsonData)
// expect to get back the conversation ID from the server after socket.on
self.socket?.on("con_create") {
(data, ack) in
print("con_create")
let json = data[1] as? JSON
self.conversationID = json!["id"].intValue
}
}
}
self.conversationID should be a whole number like 16 or 15.

Related

How to interact with Smart Contract deployed on Blockchain from Swift app

It is my first time working with smart contracts and my goal is to create a mobile app which can interact with it by calling methods to save or retrieve data. For this reason I have created a very simple contract using Remix and I have also deployed on Rinkeby testnet.
contract Storage {
uint256 number;
function store(uint256 num) public {
number = num;
}
function retrieve() public view returns (uint256){
return number;
}
}
Then I built a SwiftUI app, which has one button. When I press this button, I want to call the store method and save some int number. For example number 9. Therefore I have created a function called write which looks as following:
let myInt = 9
func write() {
let web3 = Web3.InfuraRinkebyWeb3(accessToken: "https://rinkeby.infura.io/v3/a146daf63d93490995823f0910f50118")
let walletAddress = EthereumAddress("0xc65943Fae5a554e7DCF916F8828a73E5f7b1bDCd")! // Your wallet address
let contractMethod = "store" // Contract method you want to write
let contractABI = contractABIString // Contract ABI
let contractAddress = EthereumAddress("0x2826C42354FE5B816c7E21AD9e3B395Ced512C0C")!
let abiVersion = 2 // Contract ABI version
let parameters = [myInt] as [AnyObject]
let extraData: Data = Data() // Extra data for contract method
let contract = web3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
var options = TransactionOptions.defaultOptions
options.from = walletAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
do {
contract.write(
contractMethod,
parameters: parameters,
extraData: extraData,
transactionOptions: options)
} catch {
print("error:", error)
}
Unfortunately, when I run this code, nothing is happening. I don't get any error but when I refresh the contract I see that number 9 is not passed.
I am using web3swift library, https://github.com/skywinder/web3swift/tree/master#send-erc-20-token. According to the documentation, it should be fine, but it is not working, therefore I would really appreciate some assistant to make it work or some example projects where I can take a look, because I also couldn't find anything.
I found some other project using JS and I see the people there use their private keys, maybe I also need it, but since it is not shown in the documentation, I was not sure how to use it.
The smart contract interaction requires a few initialisations steps:
Your wallet
KeyStoreManager
web3
Let's assume you already got a Metamask wallet.
Separately you need to have a separate file containing the ABI of the smartContract you want to interact with.
It is an array and having it in a Swift.String is easier.(I won't show you this step)
struct Wallet {
let address: String
let data: Data
let name: String
let isHD: Bool
}
class SmartContractInteraction {
var wallet: Wallet!
var keystoreManager: KeystoreManager!
var web3: web3!
init() {
wallet = initializeWallet()
keystoreManager = getKeyStoreManager()
web3 = initializeweb3()
}
private func initializeWallet() -> Wallet? {
let password = "PasswordMetamask"
let key = "AccountPrivateKey"
let formattedKey = key.trimmingCharacters(in: .whitespacesAndNewlines)
let dataKey = Data.fromHex(formattedKey)!
let name = "Account 1"
do {
let keystore = try EthereumKeystoreV3(privateKey: dataKey, password: password)!
let keyData = try JSONEncoder().encode(keystore.keystoreParams)
let address = keystore.addresses!.first!.address
return Wallet(address: address, data: keyData, name: name, isHD: false)
} catch {
print("wallet init failed: \(error)")
return nil
}
}
private func getKeyStoreManager() -> KeystoreManager {
let data = wallet.data
let keystoreManager: KeystoreManager
if wallet.isHD {
let keystore = BIP32Keystore(data)!
keystoreManager = KeystoreManager([keystore])
} else {
let keystore = EthereumKeystoreV3(data)!
keystoreManager = KeystoreManager([keystore])
}
return keystoreManager
}
private func initializeweb3() -> web3 {
let endpoint = "https://ropsten.infura.io/v3/....."
let web3 = web3swift.web3(provider: Web3HttpProvider(URL(string: endpoint)!)!)
web3.addKeystoreManager(keystoreManager)
return web3
}
func callSmartContract() {
let value: String = "1"
let walletAddress = EthereumAddress(wallet.address)!
let contractAddress = EthereumAddress("SmartContractAddress")!
let contractMethod = "store"
let contractABI = MyContractABI
let abiVersion = 2
let parameters = [9] as [AnyObject]
let extraData: Data = Data()
let contract = web3.contract(contractABI, at: contractAddress, abiVersion: abiVersion)!
let amount = Web3.Utils.parseToBigUInt(value, units: .wei)
var options = TransactionOptions.defaultOptions
options.value = amount
options.from = walletAddress
options.gasPrice = .automatic
options.gasLimit = .automatic
let tx = contract.write(
contractMethod,
parameters: parameters,
extraData: extraData,
transactionOptions: options)!
do {
let password = "MetamaskPassword"
let result = try tx.send(password: password)
print(result)
} catch {
print("Token Balance failed: \(error)")
}
}
}
Like this should work, I think passing the value/option.value in the smartContract call method isn't necessary, but since I don't have your ABI I prefer to not remove anything from how it worked for me. Also I am not sure about the type of the number you pass.
Feel free to edit if this works without :)

Web3Swift Interaction with custom ABI

I am trying to interact with a smart contract I set up.
Basically the goal is to set from an iOS App 5 Parameters
projectTitle
projectLocation
projectStart
projectEnd
teamType
I want the user to set those parameters and write it on the ropsten testnetwork.
I also would like to get the contract information at a later point whenever the user feels for it.
my solidity code is working properly in remix and the contract is already deployed:
pragma solidity >=0.4.22 <0.7.0;
contract ProjectContent {
string public projectTitle;
string public projectLocation;
string public projectStart;
string public projectEnd;
string public teamType;
function projectContent(string initialProjectTitle, string initialProjectLocation, string initialProjectStart, string initialProjectEnd, string initialTeamType) public {
projectTitle = initialProjectTitle;
projectLocation = initialProjectLocation;
projectStart = initialProjectStart;
projectEnd = initialProjectEnd;
teamType = initialTeamType;
}
function setContract(string newProjectTitle, string newProjectLocation, string newProjectStart, string newProjectEnd, string newTeamType) public {
projectTitle = newProjectTitle;
projectLocation = newProjectLocation;
projectStart = newProjectStart;
projectEnd = newProjectEnd;
teamType = newTeamType;
}
function getProjectTitle() public view returns (string) {
return projectTitle;
}
function getProjectLocation() public view returns (string) {
return projectLocation;
}
function getProjectStart() public view returns (string) {
return projectStart;
}
function getProjectEnd() public view returns (string) {
return projectEnd;
}
function getTeamType() public view returns (string) {
return teamType;
}
}
My problem now is that I cannot figure out how to retrieve the data from the blockchain using the web3swift library. I am doing it like so now:
class ProjectContractViewController: UIViewController, HalfModalPresentable {
#IBOutlet weak var contractABIView: UITextView!
var halfModalTransitioningDelegate: HalfModalTransitioningDelegate?
var contractABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"initialProjectTitle\",\"type\":\"string\"},{\"name\":\"initialProjectLocation\",\"type\":\"string\"},{\"name\":\"initialProjectStart\",\"type\":\"string\"},{\"name\":\"initialProjectEnd\",\"type\":\"string\"},{\"name\":\"initialTeamType\",\"type\":\"string\"}],\"name\":\"projectContent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"newProjectTitle\",\"type\":\"string\"},{\"name\":\"newProjectLocation\",\"type\":\"string\"},{\"name\":\"newProjectStart\",\"type\":\"string\"},{\"name\":\"newProjectEnd\",\"type\":\"string\"},{\"name\":\"newTeamType\",\"type\":\"string\"}],\"name\":\"setContract\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getProjectEnd\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getProjectLocation\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getProjectStart\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getProjectTitle\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getTeamType\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"projectEnd\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"projectLocation\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"projectStart\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"projectTitle\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"teamType\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"
let str = "0x6080604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806323a35e62146100bf57806337a4fc7d1461014f5780634a5736fd146101df5780634b04811e1461026f5780634e9d1281146102ff57806363afee221461038f578063775e6d451461051057806393ee0402146105a0578063c3e20c9f14610630578063d8045412146106c0578063dad375ff14610750578063f020cd19146108d1575b600080fd5b3480156100cb57600080fd5b506100d4610961565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101145780820151818401526020810190506100f9565b50505050905090810190601f1680156101415780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015b57600080fd5b50610164610a03565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101a4578082015181840152602081019050610189565b50505050905090810190601f1680156101d15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156101eb57600080fd5b506101f4610aa1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610234578082015181840152602081019050610219565b50505050905090810190601f1680156102615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561027b57600080fd5b50610284610b3f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102c45780820151818401526020810190506102a9565b50505050905090810190601f1680156102f15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561030b57600080fd5b50610314610bdd565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610354578082015181840152602081019050610339565b50505050905090810190601f1680156103815780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561039b57600080fd5b5061050e600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610c7b565b005b34801561051c57600080fd5b50610525610cf5565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561056557808201518184015260208101905061054a565b50505050905090810190601f1680156105925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156105ac57600080fd5b506105b5610d97565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105f55780820151818401526020810190506105da565b50505050905090810190601f1680156106225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561063c57600080fd5b50610645610e39565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561068557808201518184015260208101905061066a565b50505050905090810190601f1680156106b25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156106cc57600080fd5b506106d5610ed7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156107155780820151818401526020810190506106fa565b50505050905090810190601f1680156107425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561075c57600080fd5b506108cf600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610f79565b005b3480156108dd57600080fd5b506108e6610ff3565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561092657808201518184015260208101905061090b565b50505050905090810190601f1680156109535780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606060028054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109f95780601f106109ce576101008083540402835291602001916109f9565b820191906000526020600020905b8154815290600101906020018083116109dc57829003601f168201915b5050505050905090565b60028054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a995780601f10610a6e57610100808354040283529160200191610a99565b820191906000526020600020905b815481529060010190602001808311610a7c57829003601f168201915b505050505081565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b375780601f10610b0c57610100808354040283529160200191610b37565b820191906000526020600020905b815481529060010190602001808311610b1a57829003601f168201915b505050505081565b60048054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bd55780601f10610baa57610100808354040283529160200191610bd5565b820191906000526020600020905b815481529060010190602001808311610bb857829003601f168201915b505050505081565b60038054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c735780601f10610c4857610100808354040283529160200191610c73565b820191906000526020600020905b815481529060010190602001808311610c5657829003601f168201915b505050505081565b8460009080519060200190610c91929190611095565b508360019080519060200190610ca8929190611095565b508260029080519060200190610cbf929190611095565b508160039080519060200190610cd6929190611095565b508060049080519060200190610ced929190611095565b505050505050565b606060018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610d8d5780601f10610d6257610100808354040283529160200191610d8d565b820191906000526020600020905b815481529060010190602001808311610d7057829003601f168201915b5050505050905090565b606060048054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610e2f5780601f10610e0457610100808354040283529160200191610e2f565b820191906000526020600020905b815481529060010190602001808311610e1257829003601f168201915b5050505050905090565b60008054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ecf5780601f10610ea457610100808354040283529160200191610ecf565b820191906000526020600020905b815481529060010190602001808311610eb257829003601f168201915b505050505081565b606060038054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610f6f5780601f10610f4457610100808354040283529160200191610f6f565b820191906000526020600020905b815481529060010190602001808311610f5257829003601f168201915b5050505050905090565b8460009080519060200190610f8f929190611095565b508360019080519060200190610fa6929190611095565b508260029080519060200190610fbd929190611095565b508160039080519060200190610fd4929190611095565b508060049080519060200190610feb929190611095565b505050505050565b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561108b5780601f106110605761010080835404028352916020019161108b565b820191906000526020600020905b81548152906001019060200180831161106e57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106110d657805160ff1916838001178555611104565b82800160010185558215611104579182015b828111156111035782518255916020019190600101906110e8565b5b5090506111119190611115565b5090565b61113791905b8082111561113357600081600090555060010161111b565b5090565b905600a165627a7a72305820458843a936d80ffe49dddb0955a0c1d56d0e15f994cd5ce31b386188b2724a790029"
var contractAddress = EthereumAddress("0x11A0c067d7481240dCA57457eff77fc98dEAdE0F")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func callContract(Password: String) {
// Get from address from private key
let formattedKey = Password.trimmingCharacters(in: .whitespacesAndNewlines)
let dataKey = Data.fromHex(formattedKey )!
// ### use [passKey]
let keystore = try! EthereumKeystoreV3(privateKey: dataKey, password: "")!
let keyData = try! JSONEncoder().encode(keystore.keystoreParams)
// let address = keystore.addresses!.first!.address
let address = keystore.addresses!.first!.address
let ethAddress = EthereumAddress(address)
let infura = Web3.InfuraMainnetWeb3()
// 1
let contract = infura.contract(contractABI, at: contractAddress, abiVersion: 2)
// 2
var options = TransactionOptions.defaultOptions
options.from = keystore.addresses!.first!
// 3
let data = Data.init(hex: str)
let transactionIntermediate = contract?.method("getProjectTitle", parameters: [address] as [AnyObject], extraData: data, transactionOptions: options)
// 4
let result = transactionIntermediate!.call(transactionOptions: options)
switch result {
// 5
case .success(let res):
let ans = res["0"] as! Bool
DispatchQueue.main.async {
completion(Result.Success(ans))
}
case .failure(let error):
DispatchQueue.main.async {
completion(Result.Error(error))
}
}
}
}
I get an error for the resultsaying:
"Call can throw, but it is not marked with 'try' and the error is not handled"
and in general I find it really hard to set up the interaction with a smart contract abi.
I am already using the web3swift functionality for sending transactions at it works like a charm.
Maybe someone knows how I can record information on the blockchain and get it using web3swift.
You are close. Starting with the error "Call can throw, but it is not marked with 'try' and the error is not handled" this is caused by trying to call a contract function without using the Try Catch pattern. Do to the way web3 library is designed this pattern is necessary for all write and call methods.
// Incorrect
let result = transactionIntermediate!.call(transactionOptions: options)
// Correct
do {
let result = try transactionIntermediate!.call(transactionOptions: options)
}catch{
print("Error trying to call method \(error)")
}
Additionally, I recommend using the DispatchQueue.main.async along with Promise Kit library when making your contract calls.
ABIs are hard to read and messy, don't recommend using it to help find callable methods and parameters within the contract. Instead I would have the contract open along side Xcode and through the use of either an enum or struct containing all the contract methods that are going to be used.
// Methods available within the contract
enum ContractMethods:String {
case projectContract = "projectContent"
case setContract = "setContract"
case getProjectTitle = "getProjectTitle"
case getProjectLocation = "getProjectLocation"
case getProjectStart = "getProjectStart"
case getProjectEnd = "getProjectEnd"
case getTeamType = "getTeamType"
}
// Usage
ContractMethods.setContract.rawValue
I moved the ABI to a separate file within xcode to keep it clean. Here is link to the file.
Here is a good example to help get you started. Check out my GitHub repo for the improved version.
import UIKit
import web3swift
import PromiseKit
struct Wallet {
let address: String
let data: Data
let name:String
let isHD:Bool
}
struct HDKey {
let name:String?
let address:String
}
var password = "" // leave empty for ganache or use your wallet password
let privateKey = "<PrivateKey>" // Private key of wallet
let walletName = "MyWallet"
let contractAddress = "<ContractAddress>" // 0x11A0c067d7481240dCA57457eff77fc98dEAdE0F
let endpoint = URL(string:"http://127.0.0.1:7545")! // Im using Ganache but it might look like endpoint = URL(string:"https://rinkeby.infura.io/v3/<APIKEY>")!
let abiVersion = 2
class ViewController: UIViewController {
// Mock data used within contract
let projectTitle = "HouseSiding"
let projectLocation = "299 Race Ave. Dacula, GA 30019"
let projectStart = "May 14, 2021"
let projectEnd = "June 15, 2021"
let teamType = "Collaboration"
var web3:web3?
var contract:web3.web3contract?
override func viewDidLoad() {
super.viewDidLoad()
// 1. Create wallet using a private key
let formattedKey = privateKey.trimmingCharacters(in: .whitespacesAndNewlines)
let dataKey = Data.fromHex(formattedKey)!
let keyStore = try! EthereumKeystoreV3(privateKey:dataKey, password: password)!
let keyData = try! JSONEncoder().encode(keyStore.keystoreParams)
let address = keyStore.addresses!.first!.address
let wallet = Wallet(address: address, data: keyData, name: walletName, isHD: false)
// 2. Construct web3 and keystoreManager
do {
web3 = try Web3.new(endpoint)
let data = wallet.data
var keystoreManager: KeystoreManager
if wallet.isHD {
let keystore = BIP32Keystore(data)!
keystoreManager = KeystoreManager([keystore])
}else{
let keystore = EthereumKeystoreV3(data)!
keystoreManager = KeystoreManager([keystore])
}
print(keystoreManager.addresses)
web3!.addKeystoreManager(keystoreManager)
let ethContractAddress = EthereumAddress(contractAddress, ignoreChecksum: true)!
contract = web3!.contract(contractABI, at: ethContractAddress, abiVersion: abiVersion)!
}catch{
print ("Failed to construct contract and/or keystoreManager \(error)")
}
// 3. Create and callout a contract method
//let parameters = [projectTitle,projectLocation,projectStart,projectEnd,teamType] as [AnyObject] // parameters used to created a new project
let parameters = [] as [AnyObject] // no parameters
let response = Promise<Any> { seal in
DispatchQueue.global().async {
// Catch errors within async call
do {
// No extra data for method call
let extraData: Data = Data()
// Options for method call
var options = TransactionOptions.defaultOptions
options.from = EthereumAddress(wallet.address)! // current wallet address
// Leave automatic for gas
options.gasPrice = .automatic
options.gasLimit = .automatic
// Calling get Project title from contract
// NOTE: First call setContract with parameters
let tx = self.contract!.method("getProjectTitle",
parameters: parameters,
extraData: extraData,
transactionOptions: options)
// Depending on the type of call a password might be needed
//if password != nil {
//let result = try tx!.send(password: password)
// seal.resolve(.fulfilled(true))
//}else{
let result = try tx!.call()
// fulfill are result from contract
let anyResult = result["0"] as Any
seal.resolve(.fulfilled(anyResult))
//}
}catch {
// error
seal.reject(error)
}
}
}
response.done({result in
print(result) // Optional(HouseSiding)
})
}
}

Marvel API 409 response, "You must provide a user key"

Wondering if anyone can help me here:
private static func getURLRequestData(completion: #escaping (Data?) -> ()) {
// Gets the raw JSON Data
let session = URLSession(configuration: .default)
guard let url = URL(string: urlString) else { return }
var urlRequest = URLRequest(url: url)
let headers = [
"ts" : ts,
"apikey" : apiKey,
"hash" : hash,
"limit" : limit,
"orderBy" : orderedBy
]
urlRequest.allHTTPHeaderFields = headers
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print(#line, error!.localizedDescription)
}
print(response)
completion(data)
}
task.resume()
}
As you can see, I am setting the headers correctly with my API Key but for some reason I'm getting a 409 return which is a missing "user key".
Has anyone experienced anything like this. For what its worth, the exact same request is working in Paw
You must provide informations according documentation link documentation here
Example:
var publickey = 'you-public-key';
var privatekey = 'you-private-key';
var ts = new Date().getTime();
var stringToHash = ts + privatekey + publickey;
var hash = md5(stringToHash);
var baseUrl = 'https://gateway.marvel.com:443/v1/public/characters';
var limit = 20;
var url = baseUrl + '?limit=' + limit + '&ts=' + ts + '&apikey=' + publickey + '&hash=' + hash;

Swift Completion & Loop Issue

Trying to download a PKG file from one of three urls. The logic basically finds the latency of a download from each download url and sets the final download url to the host with the lowest latency.
import Cocoa
import Alamofire
// Create my object via Struct
struct Package {
var latency: Double?
var name: String?
var statuscode: Int?
var download: Bool?
var downloadUrl: String?
}
// Download the package from the provided download url and return the object
func getPKG(pkgName: String, dpUrl: String, completion: #escaping (Package) -> (Package)) {
let url = URL(string: "\(dpUrl)\(pkgName)")
let parameters: Parameters = ["foo":"bar"]
Alamofire.download(url, method: .get, parameters: parameters, encoding: JSONEncoding.default, to: destination)
.downloadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
debugPrint("Download Progress...: \(progress.fractionCompleted)")
}
.validate(statusCode: 200..<399)
.response { response in
debugPrint(response.response!)
debugPrint(response.response!.statusCode)
debugPrint(response.timeline.latency)
let dlObject = Package(latency: response.timeline.latency, name: pkgName, statuscode: response.response?.statusCode, download: true, downloadUrl: dpUrl)
completion(dlObject)
}
}
var share_response = [String: Double]()
var package_sources: NSArray! = ["https://www.jss1.com/Share", "https://www.jss2.com/Share", "https://www.jss3.com/Share"]
let package_names: String = ["Dummy1.pkg", "Dummy2.pkg", "Dummy3.pkg"]
// Loop through the package sources and find the one with
// the lowest latency.
for share_url in package_sources {
getPKG(pkgName: "Dummy.pkg", dpUrl: share_url, completion: {
dlObject in
if dlObject.latency != nil {
share_response[share_url] = dlObject.latency
} else {
debugPrint("nothing yet")
}
return dlObject
})
}
let final_download_url = share_response.min { a, b in a.value < b.value }
// Here is where it breaks and responds with nil
for package in package_names {
let download_url = URL(string: final_download_url + package)
Download commands here...
}
This is done by looping through each download url and populating a dictionary with the key as the url and the value as the latency. When the script moves on to download from the "fastest" download url, it fails with nil.
I'm assuming that's because the script is moving on while the completion handler is still running and nothing is in the dictionary yet, but how would I address this?
Based on the answer from #vadian at Synchronous request using Alamofire
...
let group = DispatchGroup()
var share_response = [String: Double]()
var package_sources: NSArray! = ["https://www.jss1.com/Share", "https://www.jss2.com/Share", "https://www.jss3.com/Share"]
let package_names: String = ["Dummy1.pkg", "Dummy2.pkg", "Dummy3.pkg"]
// Loop through the package sources and find the one with
// the lowest latency.
for share_url in package_sources {
group.enter()
getPKG(pkgName: "Dummy.pkg", dpUrl: share_url, completion: {
group.leave()
dlObject in
if dlObject.latency != nil {
share_response[share_url] = dlObject.latency
} else {
debugPrint("nothing yet")
}
return dlObject
})
}
group.notify(queue: DispatchQueue.main) {
let final_download_url = share_response.min { a, b in a.value < b.value }
// Here is where it breaks and responds with nil
for package in package_names {
let download_url = URL(string: final_download_url + package)
Download commands here...
}
}

In Swift Express using Bright Futures, How To Handle Asynchronous Operations?

I'm trying to create a basic asynchronous example in SwiftExpress using BrightFutures, and failing. Here's what I've got:
class FileSystem {
class func read(fileURL:NSURL, convert:(NSData?) -> Action<AnyContent>) -> Future<Action<AnyContent>, AnyError> {
let promise = Promise<Action<AnyContent>, AnyError>()
Queue.global.async {
let fileData = NSData(contentsOfURL:fileURL)
let action = convert(fileData)
promise.success(action)
}
return promise.future
}
}
Here's the server:
import Express
import TidyJSON
import BrightFutures
import Result
let app = express()
app.views.register(JsonView())
// Parameters: JSON object {"filePath" : "<filePath>"}
app.post("/readFile") { request -> Future<Action<AnyContent>, AnyError> in
//check if JSON has arrived
guard let json = request.body?.asJSON(),
let jsonDict = json.object,
let filePath = jsonDict["filePath"],
let filePathString = filePath.string else {
return future {
var response = [
"status": "error",
"message" : "Invalid request"
]
return Result(value: Action.render(JsonView.name, context: response))
}
}
print("json: \(json)")
print("json: \(json.object)")
let url = NSURL(fileURLWithPath: filePathString)
return FileSystem.read(url, convert: { data -> Action<AnyContent> in
var response = [String:AnyObject]()
var status:String
if data == nil {
status = "error"
response["message"] = "Could not read file"
}
else {
status = "ok"
response["result"] = data!
}
response["status"] = status
return Action.render(JsonView.name, context: response)
}).onSuccess { action in
print("action: \(action)")
}
}
app.all("/*") { request in
return Action.ok("Got a unknown request.")
}
app.listen(9999).onSuccess { server in
print("Express was successfully launched on port", server.port)
}
app.run()
When I connect to this using Postman, I get a `{}' in response. I can set breakpoints, and I know the code is executing, and I know I have an error (it can't find the file-- intentional on my part), just can't see why the response doesn't have the error status and message. Ideas?
Problem solved! A single line was wrong:
var response = [String:AnyObject]()
needed to be:
var response = [String:String]()