开发者社区> 问答> 正文

oss c sdk利用CURL提供的Callback实现数据下载

     前面分享了oss c sdk使用CURL提供的Callback实现数据上传,接下来一起看一下oss c sdk使用CURL提供的Callback实现数据下载。

    下载数据常见的方式有两种:下载数据到memory、下载数据到文件。大家也可以参考oss c sdk使用CURL提供的Callback方式根据自己的需求自定义下载回调函数。首先,我们一起熟悉oss c sdk中使用的一些数据结构:

struct aos_http_response_s {
    int status;
    aos_table_t *headers;


    aos_list_t body;
    int64_t body_len;
    char *file_path;
    aos_file_buf_t* file_buf;
    int64_t content_length;


    aos_pool_t *pool;
    void *user_data;
    aos_write_http_body_pt write_body;


    aos_http_body_type_e type;
};


typedef enum {     
    BODY_IN_MEMORY = 0,     
    BODY_IN_FILE,     
    BODY_IN_CALLBACK
} aos_http_body_type_e ;


typedef int (*aos_write_http_body_pt)(aos_http_response_t *resp, const char *buffer, int len);


    看完上面的数据结构,如果前面有了解过oss c sdk使用CURL提供的Callback上传数据的过程,那么对上面的数据结构就不会陌生了。接下来我们结合具体的数据下载方式详细说明:
(1)从OSS下载数据到本地文件中
oss c sdk提供了oss_get_object_to_file接口用于将OSS上的数据下载到本地文件中。大家可以看一下这个函数的实现,我们重点看一下这个函数中 oss_init_read_response_body_to_file函数的实现:

int oss_init_read_response_body_to_file(aos_pool_t *p, const aos_string_t *filename, aos_http_response_t *resp)
{
    int res = AOSE_OK;
    aos_file_buf_t *fb = aos_create_file_buf(p);
    res = aos_open_file_for_write(p, filename->data, fb);
    if (res != AOSE_OK) {
        aos_error_log("Open write file fail, filename:%s\n", filename->data);
        return res;
    }
    resp->file_path = filename->data;
    resp->file_buf = fb;
    resp->write_body = aos_write_http_body_file;
    resp->type = BODY_IN_FILE;


    return res;
}


    注意红色部分,大家可以把这部分和上面的 aos_http_response_s数据结构联系起来,相信已经想到就是在这里设置将下载数据写入本地文件。接下来我们继续跟进,分析这些设置如何和CURL提供的Callback联系上。继续贴码:
aos_http_transport_t *aos_curl_http_transport_create(aos_pool_t *p) {     
    aos_func_u func;     
    aos_curl_http_transport_t *t;
  
    t = (aos_curl_http_transport_t *)aos_pcalloc(p, sizeof(aos_curl_http_transport_t));
  
    t->pool = p;   
    t->options = aos_default_http_transport_options;     
    t->cleanup = aos_fstack_create(p, 5);
  
    func.func1 = (aos_func1_pt)aos_transport_cleanup;     
    aos_fstack_push(t->cleanup, t, func, 1);
    
    t->curl = aos_request_get();     
    func.func1 = (aos_func1_pt)request_release;     
    aos_fstack_push(t->cleanup, t->curl, func, 1);
    
    t->header_callback = aos_curl_default_header_callback;   
    t->read_callback = aos_curl_default_read_callback;   
    t->write_callback = aos_curl_default_write_callback;     


    return (aos_http_transport_t *)t;
}



size_t aos_curl_default_write_callback (char *ptr, size_t size, size_t nmemb, void *userdata){
    int len;    int bytes;
    aos_curl_http_transport_t *t;

    t = (aos_curl_http_transport_t *)(userdata);  
    len = size * nmemb;

    if (t->controller->first_byte_time == 0) {
        t->controller->first_byte_time = apr_time_now();  
    }

    aos_curl_transport_headers_done(t);

    if (t->controller->error_code != AOSE_OK) {
        aos_debug_log("write callback abort");        
        return 0;
    }

    // On HTTP error, we expect to parse an HTTP error response        
    if (t->resp->status < 200 || t->resp->status > 299) {
        bytes = aos_write_http_body_memory(t->resp, ptr, len);        
        assert(bytes == len);
        aos_move_transport_state(t, TRANS_STATE_BODY_IN);      
        return bytes;
    }

    if (t->resp->type == BODY_IN_MEMORY && t->resp->body_len >= (int64_t)t->controller->options->max_memory_size) {        
         t->controller->reason = apr_psprintf(t->pool,
              "receive body too big, current body size: %" APR_INT64_T_FMT ", max memory size: %" APR_INT64_T_FMT,
              t->resp->body_len, t->controller->options->max_memory_size);
        t->controller->error_code = AOSE_OVER_MEMORY;
        aos_error_log("error reason:%s, ", t->controller->reason);
        return 0;
    }
    if ((bytes = t->resp->write_body(t->resp, ptr, len)) < 0) {
        aos_debug_log("write body failure, %d.", bytes);
        t->controller->error_code = AOSE_WRITE_BODY_ERROR;
        t->controller->reason = "write body failure.";
        return 0;
    }
    aos_move_transport_state(t, TRANS_STATE_BODY_IN);
    return bytes;
}

int aos_curl_transport_setup(aos_curl_http_transport_t *t) {
     ...
     curl_easy_setopt_safe(CURLOPT_WRITEFUNCTION, t->write_callback);
    ...
}

    好了,大家看完上面的代码应该对整个过程比较了解了,红色部分基本说明了oss c sdk如何调用CURL提供的 CURLOPT_WRITEFUNCTION了。其他一些具体细节大家可以看一下源码,有问题也欢迎大家反馈。

(2) 从OSS下载数据到memory中
oss c sdk提供了 oss_get_object_to_buffer接口将数据从OSS下载到memory中,有了上面的下载数据到文件实现,这里简单讲一下下载数据到内存的过程,注意几个地方:
aos_http_response_t * aos_http_response_create( aos_pool_t *p) {
    aos_http_response_t *resp;

    resp = (aos_http_response_t *)aos_pcalloc(p, sizeof(aos_http_response_t));
    resp->status = -1;
    resp->headers = aos_table_make(p, 10);
   aos_list_init(&resp->body);
    resp->type = BODY_IN_MEMORY;
    resp->body_len = 0;
    resp->pool = p;
    resp->write_body = aos_write_http_body_memory;

    return resp;
}

     初始化 aos_http_response_t (也就是 aos_http_response_s的typedef )时,默认实现将数据下载到memory,所以oss_get_object_to_buffer函数中的 oss_init_read_response_body_to_buffer也比较简单,直接使用了aos_http_response_t初始化实现部分内容:
void oss_init_read_response_body_to_buffer(aos_list_t *buffer, aos_http_response_t *resp){
    aos_list_movelist(&resp->body, buffer);
}


     well,上面说明了oss c sdk如何使用CURL提供的Callback实现下载数据的一些细节。通过今天和昨天的两个分享,大家对oss c sdk使用CURL进行数据上传和下载的过程有了一些了解,希望oss c sdk对大家或多或少有一些帮助,也希望有需要的用户能够根据自己的需求自定义数据上传和下载的Callback,实现一些比较有意思的功能。    对了,前面论坛中也有用户提到如何实现上传和下载数据进度条的功能,可能这两次的分享会对大家有一点启示,欢迎大家发挥自己的想象,丰富oss c sdk的功能。


展开
收起
yjseu 2015-10-30 22:17:03 11863 0
0 条回答
写回答
取消 提交回答
问答排行榜
最热
最新

相关电子书

更多
OSS运维进阶实战手册 立即下载
《OSS运维基础实战手册》 立即下载
OSS运维基础实战手册 立即下载