public Dictionary<BuildPlatform, System.IO.MemoryStream> BuildForPlatforms(BuildPlatform platforms, MemoryStream source, PlatformResources resources) { String platformString = ""; if ((platforms & (BuildPlatform.Android | BuildPlatform.iOS)) == (BuildPlatform.Android | BuildPlatform.iOS)) //Trace.TraceInformation("Building for Android and iOS"); //FireProgressEvent("Begin build iOS & Android", ProgressStatus.BEGIN); platformString = "Android & iOS"; else if ((platforms & BuildPlatform.Android) == BuildPlatform.Android) //Trace.TraceInformation("Building for Android"); //FireProgressEvent("Begin build Android", ProgressStatus.BEGIN); platformString = "Android"; else if ((platforms & BuildPlatform.iOS) == BuildPlatform.iOS) //Trace.TraceInformation("Building for iOS"); //FireProgressEvent("Begin build iOS", ProgressStatus.BEGIN); platformString = "iOS"; else throw new ArgumentException("unknown platform"); //create our POST request IHttpWebRequest request = CreateRequest(platforms, source, resources); request.Timeout = 600000; JavaScriptSerializer jsSerializer = new JavaScriptSerializer(); FireProgressEvent(String.Format("Uploading - {0}", platformString)); //get the url to monitor for build progress string monitorURL = null; using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { if (response.StatusCode != HttpStatusCode.OK) { String msg = String.Format("Failed to upload package. Status: {0}", response.StatusCode); throw new BuildFailureException(msg); } FireProgressEvent("Upload success"); StringBuilder sb = new StringBuilder(); using (StreamReader r = new StreamReader(response.GetResponseStream())) { while (!r.EndOfStream) sb.Append(r.ReadLine()); }//end using var postResult = jsSerializer.DeserializeObject(sb.ToString()) as Dictionary<string, object>; if (!postResult.ContainsKey("result") || String.Compare(postResult["result"].ToString(), "ok", true) != 0 || !postResult.ContainsKey("id")) { Array errors = ((Dictionary<string, object>)postResult["errors"])["__all__"] as Array; StringBuilder sbError = new StringBuilder(); if (errors != null) { foreach (string error in errors) sbError.Append(error + " "); } throw new BuildFailureException(sbError.ToString()); } monitorURL = String.Format("{0}/{1}?email={2}&password={3}", _monitorURL, postResult["id"].ToString(), HttpUtility.UrlEncode(_email), HttpUtility.UrlEncode(_password)); }//end using FireProgressEvent(String.Format("Monitoring - {0}", platformString)); //monitor and get download url(s) string androidDownloadURL = null, iOSDownloadURL = null; while (true) { IHttpWebRequest monitorRequest = _requestFactory.BuildRequest("GET", monitorURL); using (HttpWebResponse monitorResponse = monitorRequest.GetResponse() as HttpWebResponse) { if (monitorResponse.StatusCode != HttpStatusCode.OK) { String msg = String.Format("Unable to get monitoring url. Response: {0}", monitorResponse.StatusCode); throw new BuildFailureException(msg); } StringBuilder sb = new StringBuilder(); using (StreamReader r = new StreamReader(monitorResponse.GetResponseStream())) { while (!r.EndOfStream) sb.Append(r.ReadLine()); }//end using String askResponseBody = sb.ToString(); var monitorResult = jsSerializer.DeserializeObject(askResponseBody) as Dictionary<string, object>; String state = monitorResult.ContainsKey("state") ? monitorResult["state"].ToString() : null; if (String.Compare(state, "success", true) == 0) { var info = monitorResult["info"] as Dictionary<string, object>; var files = info["files"] as Dictionary<string, object>; if ((platforms & BuildPlatform.Android) == BuildPlatform.Android) androidDownloadURL = files["android"].ToString(); if ((platforms & BuildPlatform.iOS) == BuildPlatform.iOS) iOSDownloadURL = files["ios"].ToString(); break; } else if (String.Compare(state, "failure", true) == 0) { String msg = "Build failure"; //TODO: Spit out the whole reason, including stack trace if we can get it from the server throw new BuildFailureException(msg); } else if (String.Compare(state, "pending", true) != 0) //not pending, unknown status { String msg = String.Format("Build failure. Unexpected state {0}", state); throw new BuildFailureException(msg); }//end if }//end using }//end while(true) FireProgressEvent("Downloading packages"); //download the package(s) Dictionary<BuildPlatform, MemoryStream> ret = new Dictionary<BuildPlatform, MemoryStream>(); if ((platforms & BuildPlatform.Android) == BuildPlatform.Android) { FireProgressEvent("Downloading - Android"); IHttpWebRequest dlReq = _requestFactory.BuildRequest("GET", androidDownloadURL); dlReq.Timeout = 600000; using (HttpWebResponse dlResp = (HttpWebResponse)dlReq.GetResponse()) { if (dlResp.StatusCode != HttpStatusCode.OK) { String msg = String.Format("Unable to get Android download url. Response: {0}", dlResp.StatusCode); throw new BuildFailureException(msg); } //save to memory stream MemoryStream ms = new MemoryStream(); using (Stream r = dlResp.GetResponseStream()) { byte[] buff = new byte[2048]; int bytesRead = 0, totalBytesRead = 0; while ((bytesRead = r.Read(buff, 0, buff.Length)) > 0) { ms.Write(buff, 0, bytesRead); totalBytesRead += bytesRead; //FireProgressEvent(String.Format("Downloaded {0} bytes", totalBytesRead), ProgressStatus.INPROGRESS); }//end while }//end using ms.Position = 0; ret.Add(BuildPlatform.Android, ms); }//end using }//end if if ((platforms & BuildPlatform.iOS) == BuildPlatform.iOS) { FireProgressEvent("Downloading - iOS"); IHttpWebRequest dlReq = _requestFactory.BuildRequest("GET", iOSDownloadURL); dlReq.Timeout = 600000; using (HttpWebResponse dlResp = (HttpWebResponse)dlReq.GetResponse()) { if (dlResp.StatusCode != HttpStatusCode.OK) { String msg = String.Format("Unable to get iOS download url. Response: {0}", dlResp.StatusCode); throw new BuildFailureException(msg); } //save to memory stream MemoryStream ms = new MemoryStream(); using (Stream r = dlResp.GetResponseStream()) { byte[] buff = new byte[2048]; int bytesRead = 0, totalBytesRead = 0; while ((bytesRead = r.Read(buff, 0, buff.Length)) > 0) { ms.Write(buff, 0, bytesRead); totalBytesRead += bytesRead; //FireProgressEvent(String.Format("Downloaded {0} bytes", totalBytesRead), ProgressStatus.INPROGRESS); }//end while }//end using ms.Position = 0; ret.Add(BuildPlatform.iOS, ms); }//end using }//end if return ret; }
private IHttpWebRequest CreateRequest(BuildPlatform platforms, MemoryStream source, PlatformResources resources) { IHttpWebRequest request = _requestFactory.BuildRequest("POST", _serviceURL); //add our headers request.Accept = "application/json"; request.ContentType = String.Format("multipart/form-data; boundary={0}", BOUNDARY); Dictionary<string, string> nameValues = new Dictionary<string, string>(); Dictionary<string, Tuple<string, MemoryStream>> nameStreams = new Dictionary<string, Tuple<string, MemoryStream>>(); nameValues.Add("email", _email); nameValues.Add("password", _password); source.Position = 0; nameStreams.Add("src_zip", new Tuple<string, MemoryStream>("src.zip", source)); //Android if ((platforms & BuildPlatform.Android) == BuildPlatform.Android) { resources.AndroidKeystore.Position = 0; nameStreams.Add("and_keystore", new Tuple<string, MemoryStream>(resources.AndroidKeystoreFileName, resources.AndroidKeystore)); nameValues.Add("and_keypass", resources.AndroidKeyPassword); nameValues.Add("and_storepass", resources.AndroidKeystorePassword); nameValues.Add("and_keyalias", resources.AndroidKeyAlias); }//end if //iOS if ((platforms & BuildPlatform.iOS) == BuildPlatform.iOS) { resources.iOSCertificate.Position = 0; resources.iOSProfile.Position = 0; nameStreams.Add("ios_certificate", new Tuple<string, MemoryStream>(resources.iOSCertificateFileName, resources.iOSCertificate)); nameStreams.Add("ios_profile", new Tuple<string, MemoryStream>(resources.iOSProfileFileName, resources.iOSProfile)); nameValues.Add("ios_password", resources.iOSCertificatePassword); }//end if //build the body using (Stream s = request.GetRequestStream()) { //add our form text values foreach (String name in nameValues.Keys) { String line = String.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", BOUNDARY, name, nameValues[name]); byte[] buff = Encoding.UTF8.GetBytes(line); s.Write(buff, 0, buff.Length); }//end foreach //add our form files foreach (String name in nameStreams.Keys) { String line = String.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\";filename=\"{2}\"\r\nContent-Type: application/base64\r\n\r\n", BOUNDARY, name, nameStreams[name].Item1); //stream the description byte[] buff = Encoding.UTF8.GetBytes(line); s.Write(buff, 0, buff.Length); //stream the file buff = new byte[nameStreams[name].Item2.Length]; nameStreams[name].Item2.Read(buff, 0, buff.Length); //buff = nameStreams[name].Item2.GetBuffer();//File.ReadAllBytes(namePaths[name]); s.Write(buff, 0, buff.Length); //stream endline buff = Encoding.UTF8.GetBytes(Environment.NewLine); s.Write(buff, 0, buff.Length); }//end foreach //end our form data String endLine = String.Format("--{0}--", BOUNDARY); byte[] endBuff = Encoding.UTF8.GetBytes(endLine); s.Write(endBuff, 0, endBuff.Length); }//end using return request; }