Reputation: 1665
I am trying to access the token returned from the Firebase function twilioToken
with Swift as I did with Redux JS. I attached my code I used for JS so I can mimic that with Swift, but not sure how to access the result.token
from the firebase function call. Am I missing something here? Do I need to get the value from the https request differently or am I close with my current code? Let me know if I need to elaborate, thanks!
Current error on output.token
is Value of tuple type 'Void' has no member 'token'
.
Attempted Swift code:
import UIKit
import MBProgressHUD
import FirebaseFunctions
class CallRoomVC: UIViewController {
private var appDelegate: AppDelegate!
private var userSession: UserSession = FirebaseUserSession.shared
lazy var functions = Functions.functions()
override func viewDidLoad() {
super.viewDidLoad()
appDelegate = UIApplication.shared.delegate as? AppDelegate
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let user = userSession.user else {
fatalError("User instance must be created")
}
var output = functions.httpsCallable("twilioToken").call(["uid": user.id]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
// ...
// or
// print("Result: \(result.token)")
}
}
if (output != nil) {
print("Result: \(output.token)")
}
}
}
Firebase Function:
"use strict";
const functions = require("firebase-functions");
const admin = require("firebase-admin");
// eslint-disable-next-line import/no-extraneous-dependencies
const google_cloud_logging = require("@google-cloud/logging");
const twilio = require("twilio");
const cors = require("cors")({
origin: true
});
// eslint-disable-next-line import/no-extraneous-dependencies
admin.initializeApp(functions.config().firebase);
exports.twilioToken = functions.https.onRequest((req, res) => {
return cors(req, res, () => {
const token = new twilio.jwt.AccessToken(
"xxxxxxxxxxxxxx", // Account ID
"xxxxxxxxxxxxxx", // API Key SID
"xxxxxxxxxxxxxx" // API Key Secret
);
token.identity = req.query.uid;
token.addGrant(new twilio.jwt.AccessToken.VideoGrant());
console.log("Sending token: ", token);
res.status(200).send({ token: token.toJwt() });
});
});
JS Redux code:
function* getTokenSaga(action) {
const token = yield call(
rsf.functions.call,
"twilioToken",
{
uid: action.uid
},
{
method: "GET"
}
);
yield put(retrievedToken(token.token));
}
export function* twilioRootSaga() {
yield all([takeEvery(types.TOKEN.GET, getTokenSaga)]);
}
Upvotes: 0
Views: 893
Reputation: 1665
Phil Nash's explanation for the Swift side of things worked, but the issue lied in my Firebase function which I had to create a new function for based on the Twilio/Firebase Function API documentation:
exports.twilioTokenV2 = functions.https.onCall((data, context) => {
const AccessToken = twilio.jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
const twilioAccountSid = functions.config().twilio_api.account_sid;
const twilioApiKey = functions.config().twilio_api.key;
const twilioApiSecret = functions.config().twilio_api.secret;
// Grab uid passed in for identity
const identity = data.uid;
// Grab question ID passed in for room name
const videoGrant = new VideoGrant({
room: data.qid,
});
// Create an access token which we will sign and return to the client,
// containing the grant we just created
const token = new AccessToken(twilioAccountSid, twilioApiKey, twilioApiSecret);
token.addGrant(videoGrant);
token.identity = identity;
console.log("Sending token: ", token);
return {
token: token.toJwt()
}
});
Upvotes: 0
Reputation: 73075
Twilio developer evangelist here.
Your call to the Firebase function is asynchronous, as it is making an HTTP request. The result is not returned to your output
variable, but it is available within the callback as the result
object. You need to use that result
instead, with something like this:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let user = userSession.user else {
fatalError("User instance must be created")
}
functions.httpsCallable("twilioToken").call(["uid": user.id]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
}
if let token = (result?.data as? [String: Any])?["token"] as? String {
print("Result: \(token)")
}
}
}
This example was adapted from the Firebase documentation here.
Let me know if it helps at all.
Upvotes: 1