Skip to content
This repository has been archived by the owner on Oct 6, 2020. It is now read-only.

Commit

Permalink
Merge pull request #46 from MindFlavor/feature/get_block_list
Browse files Browse the repository at this point in the history
Implemented get_block_list with tests
  • Loading branch information
MindFlavor authored Jun 9, 2018
2 parents 6cadcb9 + 5390a06 commit d510304
Show file tree
Hide file tree
Showing 13 changed files with 463 additions and 129 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "azure_sdk_for_rust"
version = "0.7.2"
version = "0.8.0"
description = "Rust wrappers around Microsoft Azure REST APIs"
readme = "README.md"
authors = ["Francesco Cogno <[email protected]>", "Max Gortman <[email protected]>", "Dong Liu <[email protected]>"]
Expand Down Expand Up @@ -28,12 +28,12 @@ quick-error = "1.2.2"
serde = "1.0.66"
serde_derive = "1.0.66"
serde_json = "1.0.19"
serde-xml-rs = "0.2.1"
time = "0.1.40"
tokio-core = "0.1.17"
url = "1.7.0"
uuid = "0.6.5"
uuid = { version = "0.6", features = ["v4"] }
rust-crypto = "0.2.36"
failure = "0.1.1"
smallvec = { version = "0.6", features = ["serde"] }

[features]
Expand Down
20 changes: 18 additions & 2 deletions examples/put_block_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use azure_sdk_for_rust::{
storage::blob::{Blob, BlobType, PUT_BLOCK_OPTIONS_DEFAULT}, storage::client::Client,
};

use azure_sdk_for_rust::storage::blob::{put_block_list, BlobBlockType, BlockList};
use azure_sdk_for_rust::storage::blob::{
get_block_list, put_block_list, BlobBlockType, BlockList, BlockListType,
};

use hyper::mime::Mime;

Expand Down Expand Up @@ -131,14 +133,28 @@ fn code() -> Result<(), Box<Error>> {
});

let block_list = core.run(future)?;
println!("computed block list == {:?}", block_list);

let future = get_block_list(
&client,
&(&container_name as &str, name),
&BlockListType::All,
None,
None,
None,
None,
);

let received_block_list = core.run(future)?;
println!("current block list: {:?}", received_block_list);

// now we can finalize the blob with put_block_list
let future = put_block_list(
&client,
&(&container_name as &str, name),
None,
None,
&block_list,
&received_block_list.block_list.into(),
).map(|_| {
println!("blob finalized!");
});
Expand Down
28 changes: 6 additions & 22 deletions src/azure/core/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use hyper;
use hyper::StatusCode;
use native_tls;
use serde_json;
use serde_xml_rs;
use std;
use std::io::Error as IOError;
use std::num;
Expand Down Expand Up @@ -165,6 +166,11 @@ quick_error! {
display("Native TLS error: {}", err)
cause(err)
}
SerdeXMLDeserializationError(err:serde_xml_rs::Error) {
from()
display("XML deserialization error: {}", err)
cause(err)
}
}
}

Expand Down Expand Up @@ -198,10 +204,6 @@ quick_error! {
from()
display("Parsing error: {:?}", err)
}
BlockListParseError(err: BlockListParseError){
from()
display("Block list XML parsing error: {:?}", err)
}
}
}

Expand All @@ -211,24 +213,6 @@ impl From<()> for AzureError {
}
}

#[derive(Debug, Fail)]
pub enum BlockListParseError {
#[fail(display = "invalid BlockList XML")]
InvalidBlockListXML,
#[fail(display = "Invalid Block type: {}", name)]
InvalidBlockType { name: String },
#[fail(display = "Token not found: {}", token)]
TokemNotFound { token: String },
#[fail(display = "Gneric parse error")]
GenericParseError,
}

impl std::convert::From<std::option::NoneError> for BlockListParseError {
fn from(_: std::option::NoneError) -> Self {
BlockListParseError::GenericParseError
}
}

#[inline]
pub fn extract_status_headers_and_body(
resp: hyper::client::FutureResponse,
Expand Down
3 changes: 3 additions & 0 deletions src/azure/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ define_encode_set! {
'+', '-', '&'
}
}

use uuid::Uuid;
pub type RequestId = Uuid;
11 changes: 11 additions & 0 deletions src/azure/storage/blob/blob_block_with_size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use azure::storage::blob::BlobBlockType;
use std::borrow::Borrow;

#[derive(Debug, Clone, PartialEq)]
pub struct BlobBlockWithSize<T>
where
T: Borrow<str>,
{
pub block_list_type: BlobBlockType<T>,
pub size_in_bytes: u64,
}
110 changes: 17 additions & 93 deletions src/azure/storage/blob/block_list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use azure::core::errors::BlockListParseError;
use azure::storage::blob::BlobBlockType;
use azure::storage::blob::{BlobBlockType, BlockWithSizeList};
use std::borrow::Borrow;
use std::convert::TryFrom;

#[derive(Default, Debug, Clone, PartialEq)]
pub struct BlockList<T>
Expand All @@ -11,67 +9,6 @@ where
pub blocks: Vec<BlobBlockType<T>>,
}

impl<'a> TryFrom<&'a str> for BlockList<&'a str> {
type Error = BlockListParseError;

fn try_from(xml: &'a str) -> Result<Self, Self::Error> {
// this is terrible XML parsing but will do temporarily.
// at least we are not copying strings around.
// we assume here the XML is composed by
// single byte chars. It should (base64 encoding should
// comply) but if we get unpleasant errors
// this can be a place to start looking
trace!("BlockList::try_from called with xml == \"{}\"", xml);

let mut bl = BlockList { blocks: Vec::new() };

let begin = xml[..].find("<BlockList>")? + "<BlockList>".len();
let end = xml[begin..].find("</BlockList>")? + begin;

debug!("begin == {}, end == {}", begin, end);

let mut cur = begin;

while cur < end {
debug!("cur == {}", cur);

let tagbegin = xml[cur..].find('<')? + cur + 1;
let tagend = xml[cur..].find('>')? + cur;

debug!("tagbegin == {}, tagend == {}", tagbegin, tagend);
let node_type = &xml[tagbegin..tagend];

debug!("{}", node_type);
if node_type == "/BlockList" {
break;
}

cur = tagend + 1;

let close_tag = format!("</{}>", node_type);
let close_pos = xml[cur..].find(&close_tag)? + cur;

let id = &xml[cur..close_pos];
debug!("id == {}", id);

cur = close_pos + close_tag.len() + 1;

bl.blocks.push(match node_type {
"Committed" => BlobBlockType::Committed(id),
"Uncommitted" => BlobBlockType::Uncommitted(id),
"Latest" => BlobBlockType::Latest(id),
_ => {
return Err(BlockListParseError::InvalidBlockType {
name: node_type.to_owned(),
})
}
});
}

Ok(bl)
}
}

impl<'a> BlockList<&'a str> {
pub fn to_owned(&self) -> BlockList<String> {
let mut bl: BlockList<String> = BlockList {
Expand All @@ -90,6 +27,19 @@ impl<'a> BlockList<&'a str> {
}
}

impl<T> From<BlockWithSizeList<T>> for BlockList<T>
where
T: Borrow<str> + Default,
{
fn from(b: BlockWithSizeList<T>) -> BlockList<T> {
let mut bl = BlockList::default();
for block in b.blocks {
bl.blocks.push(block.block_list_type);
}
bl
}
}

impl<T> BlockList<T>
where
T: Borrow<str>,
Expand Down Expand Up @@ -123,42 +73,16 @@ mod test {
use super::*;

#[test]
fn try_parse() {
let range = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
<BlockList>
<Committed>numero1</Committed>
<Uncommitted>numero2</Uncommitted>
<Uncommitted>numero3</Uncommitted>
<Latest>numero4</Latest>
</BlockList>";

let bl = BlockList::try_from(range).unwrap();
assert!(bl.blocks.len() == 4);
assert!(bl.blocks[0] == BlobBlockType::Committed("numero1"));
assert!(bl.blocks[1] == BlobBlockType::Uncommitted("numero2"));
assert!(bl.blocks[2] == BlobBlockType::Uncommitted("numero3"));
assert!(bl.blocks[3] == BlobBlockType::Latest("numero4"));
}

#[test]
fn to_xml_and_then_parse() {
fn to_xml() {
let mut blocks = BlockList { blocks: Vec::new() };
blocks.blocks.push(BlobBlockType::Committed("numero1"));
blocks.blocks.push(BlobBlockType::Uncommitted("numero2"));
blocks.blocks.push(BlobBlockType::Uncommitted("numero3"));
blocks.blocks.push(BlobBlockType::Latest("numero4"));

let retu: &str = &blocks.to_xml();

let bl2 = BlockList::try_from(retu).unwrap();
assert!(bl2.blocks.len() == 4);
assert!(blocks == bl2);
let _retu: &str = &blocks.to_xml();

let bl_owned = bl2.to_owned();
assert!(bl_owned.blocks[0] == BlobBlockType::Committed(String::from("numero1")));
assert!(bl_owned.blocks[1] == BlobBlockType::Uncommitted(String::from("numero2")));
assert!(bl_owned.blocks[2] == BlobBlockType::Uncommitted(String::from("numero3")));
assert!(bl_owned.blocks[3] == BlobBlockType::Latest(String::from("numero4")));
// to assert with handcrafted XML
}

}
5 changes: 5 additions & 0 deletions src/azure/storage/blob/block_list_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub enum BlockListType {
Committed,
Uncommitted,
All,
}
Loading

0 comments on commit d510304

Please sign in to comment.