1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
use reqwest::header::{ACCEPT, CONTENT_TYPE, COOKIE, USER_AGENT}; use snafu::{ResultExt, Snafu}; use crate::{ auth_cookie::get_auth_cookie, cli::UploadCommand, common_setup, vfs::{RealFetcher, Vfs, WatchMode}, }; #[derive(Debug, Snafu)] pub struct UploadError(Error); #[derive(Debug, Snafu)] enum Error { #[snafu(display( "Rojo could not find your Roblox auth cookie. Please pass one via --cookie.", ))] NeedAuthCookie, #[snafu(display("XML model file encode error: {}", source))] XmlModel { source: rbx_xml::EncodeError }, #[snafu(display("HTTP error: {}", source))] Http { source: reqwest::Error }, #[snafu(display("Roblox API error: {}", body))] RobloxApi { body: String }, } pub fn upload(options: UploadCommand) -> Result<(), UploadError> { Ok(upload_inner(options)?) } fn upload_inner(options: UploadCommand) -> Result<(), Error> { let cookie = options .cookie .clone() .or_else(get_auth_cookie) .ok_or(Error::NeedAuthCookie)?; log::trace!("Constructing in-memory filesystem"); let vfs = Vfs::new(RealFetcher::new(WatchMode::Disabled)); let (_maybe_project, tree) = common_setup::start(&options.absolute_project(), &vfs); let inner_tree = tree.inner(); let root_id = inner_tree.get_root_id(); let root_instance = inner_tree.get_instance(root_id).unwrap(); let encode_ids = match root_instance.class_name.as_str() { "DataModel" => root_instance.get_children_ids().to_vec(), _ => vec![root_id], }; let mut buffer = Vec::new(); log::trace!("Encoding XML model"); let config = rbx_xml::EncodeOptions::new() .property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown); rbx_xml::to_writer(&mut buffer, tree.inner(), &encode_ids, config).context(XmlModel)?; let url = format!( "https://data.roblox.com/Data/Upload.ashx?assetid={}", options.asset_id ); log::trace!("POSTing to {}", url); let client = reqwest::Client::new(); let mut response = client .post(&url) .header(COOKIE, format!(".ROBLOSECURITY={}", &cookie)) .header(USER_AGENT, "Roblox/WinInet") .header("Requester", "Client") .header(CONTENT_TYPE, "application/xml") .header(ACCEPT, "application/json") .body(buffer) .send() .context(Http)?; if !response.status().is_success() { return Err(Error::RobloxApi { body: response.text().context(Http)?, }); } Ok(()) }