扫码传文件
背景
什么是扫码传文件
基本原理
在设备端下载得到文件后,可自行根据文件格式,调起响应的应用/服务来打开用户文件,提供流畅的体验
SDK概述
本文档主要介绍百度网盘Panlink C++ SDK的安装和使用。使用SDK前,需要先了解panlink文件提取的基本原理。
运行环境
Panlink SDK使用Golang编写,支持交叉编译成各种运行环境的Runtime。
目录结构:
├─src/baidu.com/panlink
│ ├─example // 示例代码
│ ├─golog // 日志库
│ ├─panlink
│ ├─panlink_test.go // Panlink接口封装,单元测试
│ ├─panlink.go // Panlink接口封装
│ └─sign.go // 签名函数
│ ├─panlink_agent
│ ├─agent_test.go // Panlink客户端主程序,单元测试
│ ├─agent.go // Panlink客户端主程序
│ └─pullworker.go // 消息 Pull Worker
│ ├─types
│ └─errorcode.go // 错误码定义
│ └─output
│ ├─bin // example编译产出
│ ├─include // sdk 头文件
│ ├─lib // sdk lib 目录,根据运行环境,选择相应的dll/so文件
│ └─log // example 输出的日志目录
│ └─build.sh
编译方法:
// 可以直接使用output中的,安装golang运行环境
// 参考:https://golang.org/doc/install
sh build.sh
目前发布的SDK压缩包中,已经包含了针对各个平台编译的动态链接库文件,如没有对应平台的库文件,则可联系我们提供。
初始化
在使用SDK前,需要向网盘申请AppID、SK和DeviceType。
参数 | 说明 |
---|---|
AppID | 应用ID,第三方开发者的唯一标识 |
SK | 和AppID对应的鉴权密钥,应该尽量避免将SK分发到提供给用户的客户端上 |
DeviceType | 设备类型标识,一个AppID下可以有多个DeviceType,用来唯一标识一种接入设备类型,当有多种设备类型时,可以申请多个,DeviceType由网盘为开发者分配 |
目前网盘提供 https://pan.baidu.com 作为服务域名
PanlinkAgent
PanlinkAgent为第三方开发者实现了临时设备标识的申请,文件下发消息的长轮询,并通过回调函数的方式通知第三方开发者。
配置参数
参数的设置,请参考example程序:
typedef struct {
// 网盘服务器地址 const char* PanlinkServerHost; // 开发者参数,AppID和SK int AppID; const char* SK; const char* DeviceType; // 本机的唯一设备ID,可以使用mac地址,或者设备SN码 const char* DeviceID; // 请求UUID、消息错误时的重试间隔,单位为s,默认为2s int RequestErrorWaitSecond; // 在当前UUID过期前多久,请求新的UUID,默认为60 int RequestUUIDBufferSecond; // 拉取UUID内的消息时,最多包含多少个消息,最大为20,默认为:1 int PullLimit; // 最多拉取多少个最近的UUID的消息,默认为2 int MaxPullWorkerLimit; // 连接相关信息,建议不要修改,可以使用默认参数 // 最多空闲连接数,默认:3 int MaxIdleConns; // 空闲连接的最大空闲时间,默认:2s int IdleConnTimeoutSecond; // 连接超时时间,默认:5s int ConnectTimeoutSecond; // 请求超时时间,默认:5s int RequestTimeoutSecond; // tcp keepalive间隔,默认:30s int KeepAliveSecond; // 长轮询的请求超时时间,默认:100s int LongPullRequestTimeoutSecond;
}PanlinkAgentConfig;
初始化方法:
// PanlinkAgent对象全局只能有一个,当多次初始化时,会导致前一个对象被覆盖,可能会引起内存泄露,对于需要停止更新和拉取UUID时,使用StopAgent()和StartAgent()来启停Agent对象。
int InitPanlinkAgent(PanlinkAgentConfig* p0);
UUID申请
启动PanlinkAgent的接口:
int StartAgent();
启动PanlinkAgent后,Agent向网盘服务器申请临时设备标识,申请到的临时设备标识会包含以下信息:
typedef struct {
// 错误码,错误码为0时表示结果正常
int ErrNo;
// 错误消息,当错误码不为0时,可打印错误消息,以便定位错误原因
char* ErrMsg;
// UUID,设备临时标识
char* UUID;
// 二维码url,必须使用该url来展示二维码,以便网盘客户端正确识别设备身份
char* QRUrl;
// Time To Live,UUID的剩余有效时长,单位秒
int TTL;
// 过期的时间戳,单位秒
int ExpireAt;
}UUIDCallBackData;
UUID自动更新
在二维码将要过期时,Panlink Agent会向服务器更新UUID,此时旧的UUID和新申请到的UUID均可以用于文件提取,同时有效的UUID个数可通过PanlinkAgentConfig.MaxPullWorkerLimit
来设置。通过PanlinkAgentConfig.RequestUUIDBufferSecond
参数可用于配置在当前UUID过期前多久更新UUID。
UUID手动强制刷新
强制更新接口: int RefreshUUID();
强制更新的结果,会通过 UUIDCallBackFn 回调函数返回给开发者。
UUID二维码生成
调用以下函数来根据UUID生成二维码:
int GetQRUrl(UUIDCallBackData* uuid, int level, int size);
参数说明:
- UUIDCallBackData结构体中,`UUIDCallBackData.UUID`为用于生成二维码的UUID,`UUIDCallBackData.QRUrl`为用于接收二维码url的变量
- level的取值表示二维码抗遮挡等级:0 low、1 medium、2 high、3 highest
- size的取值表示二维码大小,参考取值为:256
返回值说明:
- 返回值为0时,表示生成成功
- 返回值不为0时,表示失败
文件下发消息的拉取
PanlinkAgent会根据UUID向网盘服务器以长轮询的方式查询是否有新的消息发送给对应的UUID。
收到文件下发消息后,会用以下结构体向开发者传递文件下载消息,一次最多会下发20个文件下载地址,具体可通过PanlinkAgentConfig.PullLimit
参数来设置:
typedef struct { // 文件名,Golang 字符串编码是 utf-8 char* Filename; // 下载地址,从该地址可以得到原始文件 char* Dlink; }FileInfo;
typedef struct { // 错误码,错误码为0时表示结果正常 int ErrNo; // 错误消息,当错误码不为0时,可打印错误消息,以便定位错误原因 char* ErrMsg; // 文件个数 int ListCnt; // 文件列表数组,个数由 ListCnt 指定 FileInfo* list; }PullCallBackData;
回调函数
开发者需要实现两个回调函数,分别用户UUID二维码的更新和文件下载消息的接收。需要注意的是,回调接口传入的参数UUIDCallBackData
和PullCallBackData
的有效期仅在回调函数内有效,回调函数运行结束后,便会回收对应的内存空间,故对于需要保留的消息,需要拷贝到其他用户变量中。
typedef void (*UUIDCallBackFn) (UUIDCallBackData*);
typedef void (*PullCallBackFn) (PullCallBackData*);
回调函数的注册
调用以下两个函数分别用于UUID更新和文件下发消息的回调函数注册
void RegiestUUIDCallBack(UUIDCallBackFn p0);
void RegiestPullCallBack(PullCallBackFn p0);
回调函数参考实现
需要注意的是,在 UUIDCallBackData 中,UUIDCallBackData.QRUrl 不会自动返回,需要调用 GetQRUrl 函数来生成业务上需要的指定冗余度和大小的二维码。QRUrl的空间回收需要业务上自己实现。
void uuidCallBackFn(UUIDCallBackData* data) { cout << "uuidCallBackFn called " << endl;
int ret = GetQRUrl(data, 1, 256); if (ret != 0) { char * err = LastError(); if (err != NULL) { cout << "GetQRUrl err, code=" << ret << " err=" << err << endl; free(err); } else { cout << "GetQRUrl err, code=" << ret << " err=null" << endl; } } cout << "errno: " << data->ErrNo << endl; cout << "errmsg: " << data->ErrMsg << endl; cout << "uuid: " << data->UUID << endl; cout << "qrurl: " << data->QRUrl << endl; cout << "ttl: " << data->TTL << endl; cout << "expireat: " << data->ExpireAt << endl; if (data->QRUrl != NULL){ free(data->QRUrl); }
}
void pullCallBackFn(PullCallBackData* data) { cout << "pullCallBackFn called " << endl; cout << "errno: " << data->ErrNo << endl; cout << "errmsg: " << data->ErrMsg << endl; cout << "listCnt: " << data->ListCnt << endl; for (int i = 0; i < data->ListCnt; ++i) { cout << "list[" << i << "].Filename: " << data->list[i].Filename << endl; cout << "list[" << i << "].Dlink: " << data->list[i].Dlink << endl; } }
异常处理
接口调用时,返回值不为0,表示遇到异常,获取异常的描述信息可以通过LastError()接口,该接口返回的字符串需要业务方自行回收内存空间。
参考示例:
PanlinkAgentConfig config; int ret = InitPanlinkAgent(&config); if (ret != 0){ char * err = LastError(); if (err != NULL) { cout << "init panlink agent err, code=" << ret << " err=" << err << endl; free(err); } else { cout << "init panlink agent err, code=" << ret << " err=null" << endl; }
return ret;
}
停止Agent
需要提供UUID更新和文件下发消息接收时,调用以下函数:
int StopAgent();
PanlinkClient
暂不直接提供PanlinkClient的调用,优先使用PanlinkAgent来实现。
调试
Panlink SDK内嵌了日志库,可以通过以下两个函数来设置日志级别和日志文件输出位置,以便于调试。在没有设置SetLogPath
时,日志会输出到标准错误输出(Stderr)。当需要关闭日志输出时,可以将日志级别设置为:LEVEL_EMERGENCY
void SetLogLevel(int p0);
void SetLogPath(char* p0);
日志级别
需要调试时,可以将日志级别设为 LEVEL_DEBUG
const int LEVEL_EMERGENCY = 0;
const int LEVEL_ALERT = 1;
const int LEVEL_CRITICAL = 2;
const int LEVEL_ERROR = 3;
const int LEVEL_WARNING = 4;
const int LEVEL_NOTICE = 6;
const int LEVEL_INFO = 7;
const int LEVEL_DEBUG = 8;
const int LEVEL_VERBOSE = 9;
EXAMPLE
example/host.cpp