展示eTS+PA+Serverless调试过程视频
通过前面两篇帖子ArkUI eTS 计算十二生肖和ArkUI eTS PA计算十二生肖[Service Ability]都是简单同步计算出结果返回,今天我们来个异步计算结果返回,这里用到了Serverless云函数来计算十二生肖,值得注意的是,云函数是异步的,不能马上返回结果,所以通过了订阅事件来获取计算出结果,有时候简单的事情复杂化,可以让我们学到更多的知识,让eTS + PA + Serverless 动起来吧!!!
首次使用云函数服务前,需要先启用此服务。如果您已经启用,可跳过本步骤。
启用云函数服务后,您首先需要在AGC中创建函数,并添加函数执行的代码。
let myHandler = function(event, context, callback, logger) {
let zodiac = ["猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"];
event.body = JSON.parse(event.body);
let idx = parseInt(event.body.year)%12;
let sx = zodiac[idx];
let res = new context.HTTPResponse(sx, {
"res-type": "simple example",
"faas-content-type": "json"
}, "application/json", "200");
//send info log
logger.info("this is message of debug log");
//send info log
logger.info("this is message of error log");
//send error log
logger.error("Test error log");
//send response
callback(res);
};
module.exports.myHandler = myHandler;
函数创建完成后,需要为函数添加触发器,才可调用到云函数。
函数创建后,您可以在AGC中测试函数的代码运行是否正常。
函数创建并测试成功,且创建好触发器后,您即可在您的应用程序中通过调用触发器来调起函数, 调用触发器有两种方法。
当您在创建的函数或函数别名中创建了一个HTTP类型的触发器后,在应用客户端调用函数时需要传入HTTP触发器的标识,查询方法如下:
在函数的触发器页面点击“HTTPTrigger”触发器,查看“触发URL”的后缀,获取触发器的标识,格式为“函数名-版本号”。如下图所示,“myhandlerxxxx-$latest”即为HTTP触发器标识。
如果需要在应用客户端中调用云函数,则必须集成云函数的客户端SDK。
implementation 'com.huawei.agconnect:agconnect-function-harmony:1.3.1.300'
应用集成了云函数SDK后,可以在应用内直接通过SDK API调用AGC中的云函数,云函数SDK与AGC的函数调用基于HTTPS的安全访问。
private AGConnectFunction function; function = AGConnectFunction.getInstance();
function.wrap("myhandlerxxxx-$latest").call();
function.wrap("myhandlerxxxx-$latest").call(map);
private void getWeek(String date) {
HashMap<String, String> map = new HashMap();
map.put("time", date);
function.wrap("myhandlerxxxx-$latest").call(map)
.addOnCompleteListener(new OnHarmonyCompleteListener<FunctionResult>() {
@Override
public void onComplete(HarmonyTask<FunctionResult> task) {
if (task.isSuccessful()) {
String value = task.getResult().getValue();
} else {
Exception e = task.getException();
if (e instanceof AGCFunctionException) {
AGCFunctionException functionException = (AGCFunctionException) e;
int errCode = functionException.getCode();
String message = functionException.getMessage();
}
// ...
}
}
});
}
/**
* Serverless计算十二生肖
*/
private void getBornFromServerless() {
HiLog.info(LABEL_LOG, "xx Java参数:" + year);
HashMap<String, String> map = new HashMap();
map.put("year", year + "");
function.wrap("test-zodiac-$latest").call(map)
.addOnCompleteListener(new OnHarmonyCompleteListener<FunctionResult>() {
@Override
public void onComplete(HarmonyTask<FunctionResult> task) {
if (task.isSuccessful()) {
String value = task.getResult().getValue();
HiLog.info(LABEL_LOG, "xxx Java云函数返回生肖: " + value);
born = value;
MessageParcel data = MessageParcel.obtain();
MessageParcel reply = MessageParcel.obtain();
MessageOption option = new MessageOption();
Map<String, Object> result = new HashMap<>();
result.put("code", SUCCESS);
result.put("abilityResult", born);
data.writeString(ZSONObject.toZSONString(result));
try {
remoteObjectHandler.sendRequest(100, data, reply, option);
} catch (RemoteException e) {
HiLog.error(LABEL_LOG, "xx Java发送事件失败: " + e.getMessage());
e.printStackTrace();
}
} else {
Exception e = task.getException();
if (e instanceof AGCFunctionException) {
AGCFunctionException functionException = (AGCFunctionException) e;
int errCode = functionException.getCode();
String message = functionException.getMessage();
HiLog.info(LABEL_LOG, "xxx Java ErrCode: " + errCode + ", Message: " + message);
}
}
}
});
}
@Override
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
// code是eTS传参messageCode
switch (code) {
case PLUS: {
HiLog.info(LABEL_LOG, "xx Java计算生肖");
// 读取参数数据
String dataStr = data.readString();
HiLog.info(LABEL_LOG, "xx Java读取参数" + dataStr);
Map<String, Object> param = new HashMap<>();
try {
// 把读取到字符串参数转为Map对象
param = ZSONObject.stringToClass(dataStr, Map.class);
// 从对象中获取参数年份
year = Integer.parseInt( String.valueOf(param.get("year")));
HiLog.info(LABEL_LOG, "xx Java获取到年份是: " + year);
}catch (RuntimeException e) {
HiLog.error(LABEL_LOG, "xx Java转换数据失败.");
}
// Serverless计算十二生肖,异步请求,这里先返回调用成功,然后通过订阅事件获取异步结果
born = "?";
// 返回结果当前仅支持String,对于复杂结构可以序列化为ZSON字符串上报
Map<String, Object> result = new HashMap<>();
result.put("code", SUCCESS);
result.put("abilityResult", born);
reply.writeString(ZSONObject.toZSONString(result));
break;
}
// 订阅事件
case SUBSCRIBE: {
remoteObjectHandler = data.readRemoteObject();
getBornFromServerless();
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", SUCCESS);
reply.writeString(ZSONObject.toZSONString(result));
break;
}
// 取消订阅
case UNSUBSCRIBE: {
remoteObjectHandler = null;
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", SUCCESS);
reply.writeString(ZSONObject.toZSONString(result));
break;
}
default: {
Map<String, Object> result = new HashMap<>();
result.put("code", ERROR);
result.put("abilityError", "服务器繁忙, 请稍后再试!!!");
reply.writeString(ZSONObject.toZSONString(result));
return false;
}
}
return true;
}
// Serverless云函数端计算生肖
getBorn() {
let that = this;
FeatureAbility.callAbility({
bundleName: "com.xxx.serverless",
abilityName: "com.xxx.serverless.ZodiacServiceAbility",
// abilityType: 0-Ability; 1-Internal Ability
abilityType: 0,
messageCode: 1001,
data: {year: this.year},
// syncOption(Optional, default sync): 0-Sync; 1-Async
syncOption: 0
}).then((data) => {
console.info("xx eTS返回结果是: " + data);
let jsonObj = JSON.parse(data);
if(jsonObj.code === 0) {
// 订阅事件
that.subscribe();
that.born = jsonObj.abilityResult;
}else{
AlertDialog.show({
message: jsonObj.abilityError
})
}
})
}
/**
* 订阅
*/
async subscribe() {
console.info("xx eTS订阅事件")
let that = this;
// 调用PA返回十二生肖
var result = await FeatureAbility.subscribeAbilityEvent({
bundleName: "com.xxx.serverless",
abilityName: "com.xxx.serverless.ZodiacServiceAbility",
abilityType: 0,
messageCode: 1005,
syncOption: 0
}, function(callbackData){
var callbackJson = JSON.parse(callbackData);
var obj = callbackJson.data;
if(obj.code === 0) {
console.info("xx eTS异步返回生肖是:" + obj.abilityResult);
that.born = obj.abilityResult;
}else{
AlertDialog.show({
message: obj.abilityError
})
}
console.info('xx eTS事件数据 is: ' + JSON.stringify(callbackJson.data));
});
var ret = JSON.parse(result);
if (ret.code == 0) {
console.info('xx eTS订阅成功, result:' + result);
} else {
console.error('xx eTS订阅失败, result:' + result);
}
}
/**
* 取消订阅
*/
async unsubscribe() {
console.info("xx eTS取消订阅")
// 调用PA返回十二生肖
var result = await FeatureAbility.unsubscribeAbilityEvent({
bundleName: "com.xxx.serverless",
abilityName: "com.xxx.serverless.ZodiacServiceAbility",
abilityType: 0,
messageCode: 1006,
syncOption: 0
});
var ret = JSON.parse(result);
if (ret.code == 0) {
console.info('xx eTS取消订阅成功, result:' + result);
} else {
console.error('xx eTS取消订阅失败, result:' + result);
}
}
aboutT[oDisappear() {
// 调用取消订阅
this.unsubscribe();
}
由于PA调用云函数是异步的,传参数给云函数后,不能马上返回结果,然后再返回给eTS端,这里用到了订阅事件,也就是说,像上次在Service Ability计算生肖,eTS调用完后,就会返回结果,但改为在Service Ability里调用云函数,不能马上返回结果,通过订阅事件方式来获取异步返回的结果。 项目源码在gitee上已申请开源,还在审核中,审核通过回复开源地址。