Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Upload to Rackspace using Unity Editor Menu Item

Discussion in 'Scripting' started by davalosweldon, Oct 30, 2018.

  1. davalosweldon

    davalosweldon

    Joined:
    Jan 31, 2018
    Posts:
    4
    The code below is an example for uploading a file to Rackspace Cloud in Unity2018. There are two separate classes, one for creating the menu item that will select the specified asset bundle and the other being the upload script that will be called by the previous script. It uses HTTP post requests to upload the selected file.

    The function below allows you to right click on an asset bundle and upload it. The right-click menu item will be grayed out unless the file is an AssetBundle and it's folder location is within Android within AssetBundles. This script must be placed in a folder called Editor.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.IO;
    5.  
    6. public class UploadAssetBundleAndroid : MonoBehaviour {
    7.  
    8.     [MenuItem("Assets/Upload/Android AssBun2RackS")]
    9.     private static void UploadAndroid()
    10.     {
    11.         Object obj = Selection.activeObject;
    12.         string path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
    13.         byte[] file = File.ReadAllBytes(path);
    14.         RackspaceRequests rs = new RackspaceRequests();
    15.         //Name, Rackspace Container(filepath), the file, what kind of file (for assetBundle, "application/zip")
    16.         rs.CallRequest(obj.name, "AssetBundles/unity2018/Android", file, "application/zip");
    17.     }
    18.  
    19.     // Note that we pass the [I]same[/I] menu path, and also pass "true" to the second MenuItem.
    20.     //This is the supplementary code that only allows an asset bundle in the
    21.     //android asset bundle folder to be uploaded
    22.     [MenuItem("Assets/Upload/Android AssBun2RackS", true)]
    23.     private static bool NewMenuOptionValidation()
    24.     {
    25.         Object obj = Selection.activeObject;
    26.         string path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
    27.         //Only allows you to use the menu item if it's in the android asset bundle folder and its an asset bundle.
    28.         if (path.Contains("AssetBundles/Android") && obj.GetType().Equals(typeof(DefaultAsset)))
    29.         {
    30.             return true;
    31.         }
    32.         else
    33.         {
    34.             return false;
    35.         }
    36.     }
    37. }

    This is the function that will upload the file to Rackspace cloud.

    Code (CSharp):
    1. using System.IO;
    2. using System.Text;
    3. using UnityEngine;
    4. using UnityEngine.Networking;
    5.  
    6. public class RackspaceRequests : MonoBehaviour
    7. {
    8.     //More information regarding sending and receiving rackspace requests can be found at the link below:
    9.     //https://developer.rackspace.com/docs/cloud-files/v1/
    10.    
    11.     //Server key, username, url, and point are placed here.
    12.     //IMPORTANT: to find your point, username, tenant-id, and authToken, you print the downloadHandler.text
    13.     //shown further down in the code. Your api key can be found by logging into rackspace. The url should be
    14.     //the same. Your public point will likely be different.
    15.     private string username = "your-username";
    16.     private string api_key = "Y0uR4p1K3y";
    17.     private string url = @"https://identity.api.rackspacecloud.com/v2.0/tokens";
    18.     private string publicPoint = "https://storage101.iad3.clouddrive.com/v1/MossoCloudFS_";
    19.  
    20.     private byte[] file;
    21.     private string filename;
    22.     private string container;
    23.     private string contentType;
    24.     private string filePathHolder;
    25.  
    26.     public void CallRequest(string fileN, string cont, byte[] fil, string contentT){
    27.         //sets the variable information, then starts the coroutine to upload the file to the container in rackspace
    28.         file = fil;
    29.         filename = fileN;
    30.         container = cont;
    31.         contentType = contentT;
    32.  
    33.         NewServerRequest();
    34.     }
    35.  
    36.     public void NewServerRequest()
    37.     {
    38.         //Starts building the json request with the username and api key
    39.         StringBuilder jsonRequest = new StringBuilder();
    40.         jsonRequest.Append(@"{""auth"":{""RAX-KSKEY:apiKeyCredentials"":{""username"":""");
    41.         jsonRequest.Append(username);
    42.         jsonRequest.Append(@""",""apiKey"":""");
    43.         jsonRequest.Append(api_key);
    44.         jsonRequest.Append(@"""}}}");
    45.  
    46.         //Declares the type of request
    47.         UnityWebRequest uwr = new UnityWebRequest(url, "POST");
    48.         //encodes the json request into UTF8 format
    49.         byte[] jsonToSend = new UTF8Encoding().GetBytes(jsonRequest.ToString());
    50.         //Creates upload handler with the given json byte array
    51.         uwr.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
    52.         //makes a download handler so we can get the response information from rackspace
    53.         uwr.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
    54.         //tells the UnityWebRequest the format of the information we're going to send to rackspace
    55.         uwr.SetRequestHeader("Content-Type", "application/json");
    56.         uwr.SendWebRequest();
    57.         int count = 0;
    58.         while(!uwr.isDone && !uwr.isNetworkError && !uwr.isHttpError){
    59.             count++;
    60.         }
    61.         count = 0;
    62.         //IMPORTANT: to find your point, username, tenant-id, and authToken, you print the downloadHandler.text
    63.         //The GetAuthTokenFromRequest(string readString) class gets the
    64.         //authToken from the downloadHandler.text
    65.         //To get the publicPoint string at the top of this class, I simply printed out the downloadHandler.text
    66.         //and looked for the right public point
    67.  
    68.         if (uwr.isNetworkError)
    69.         {
    70.             Debug.Log("Error while sending: " + uwr.error);
    71.         }
    72.         else
    73.         {
    74.             //Gets the tenantID, point, and authToken.. the point is a url that has your tenant ID at the end.
    75.             //I got the url from printing the downloadHandler.txt, and then removing the tenant ID from it.
    76.             string tenantID = uwr.GetResponseHeader("X-Tenant-Id");
    77.             Debug.Log("TenantID: " + tenantID);
    78.             string point = publicPoint + tenantID;
    79.             Debug.Log("Point: " + point);
    80.             string authToken = GetAuthTokenFromRequest(uwr.downloadHandler.text);
    81.             Debug.Log("authToken returned: " + authToken);
    82.  
    83.             //Making a new request to Rackspace to upload the given document to the given container.
    84.             UnityWebRequest putRequest = new UnityWebRequest(point + "/" + container + "/" + filename, "PUT");
    85.             putRequest.uploadHandler = (UploadHandler)new UploadHandlerRaw(file);
    86.             putRequest.SetRequestHeader("Content-Type", contentType);
    87.             putRequest.SetRequestHeader("X-Auth-Token", authToken);
    88.             putRequest.SendWebRequest();
    89.  
    90.             while(!putRequest.isDone && !putRequest.isNetworkError && !putRequest.isHttpError){
    91.                 count++;
    92.             }
    93.  
    94.             if (putRequest.isNetworkError)
    95.             {
    96.                 Debug.Log("put request error: " + putRequest.error);
    97.             }
    98.             else
    99.             {
    100.                 Debug.Log("Success");
    101.             }
    102.         }
    103.     }
    104.  
    105.     //Just a kinda S***ty method for parsing the json information and getting the auth token.
    106.     public string GetAuthTokenFromRequest(string readString)
    107.     {
    108.         //creates an arraylist for storing the authToken
    109.         string authToken = "";
    110.         //Creates a string reader for parsing the information returned from the http request
    111.         using (StringReader reader = new StringReader(readString))
    112.         {
    113.             //bool for knowing what section of information we're on in the return request
    114.             //NOTE: The actual string looks kinda like:
    115.             //random stuff,"token:"{"something:","somethingsomething","id:","the token id",
    116.             //"somemore:","things that don't matter"}
    117.             //So it finds the word token, then knows it's on the token section
    118.             //of the return request, then identifies the id,
    119.             //then takes the very next thing that is surrounded by quotes, which will be the actual token id.
    120.             bool onTokenSection = false;
    121.             bool onIdSection = false;
    122.             //string builder for building each full word in the request
    123.             StringBuilder sb = new StringBuilder();
    124.             //creates char array for getting each individual character from the request
    125.             char[] nextChar = { ' ' };
    126.             //reads each character for the length of the string
    127.             for (int i = 0; i < readString.Length; i++)
    128.             {
    129.                 //Finds the first "
    130.                 if (nextChar[0] == '"') //All words in the request are denoted with "quote marks"
    131.                 {
    132.                     //throws away the " currenlty queued in the char array
    133.                     reader.Read(nextChar, 0, 1);
    134.  
    135.                     //will take in chars and build a string until it reaches the next "
    136.                     while (nextChar[0] != '"')
    137.                     {
    138.                         sb.Append(nextChar);
    139.                         reader.Read(nextChar, 0, 1);
    140.                     }
    141.                     //if the string built is "token" we know that we are on the token section
    142.                     //of the return request (the section containing all of the info about the token)
    143.                     if (sb.ToString().Equals("token") || onTokenSection)
    144.                     {
    145.                         //Adds each "word"
    146.                         if (onTokenSection)
    147.                         {
    148.                             if (sb.ToString().Equals("id") || onIdSection)
    149.                             {
    150.                                 //if the "word" is id, it will say it's on the id section, and the next
    151.                                 //time it comes through, it will have the token id and break from the loop
    152.                                 authToken = sb.ToString();
    153.                                 if (onIdSection)
    154.                                 {
    155.                                     break;
    156.                                 }
    157.                                 onIdSection = true;
    158.                             }
    159.                         }
    160.                         //sets bool to know it has found the results section
    161.                         onTokenSection = true;
    162.  
    163.                         //clears the string builder
    164.                         sb.Remove(0, sb.Length);
    165.                         //reads next char to throw away the " currenty in the char array
    166.                         reader.Read(nextChar, 0, 1);
    167.                     }
    168.                     else
    169.                     {
    170.                         //if it hasn't found the word "token" or if it is not currently in the
    171.                         //token section, it throws away the word built up in the string builder                      
    172.                         sb.Remove(0, sb.Length);
    173.                     }
    174.                 }
    175.                 else
    176.                 {
    177.                     //if the char isn't ", reads in the next char
    178.                     reader.Read(nextChar, 0, 1);
    179.                 }
    180.             }
    181.         }
    182.         //After everything is finished, returns the token ID
    183.         return authToken;
    184.     }
    185. }
    186.  
    I hope this helps someone.

    Cheers,
    Weldon
     
  2. Chris-HG

    Chris-HG

    Joined:
    Aug 10, 2012
    Posts:
    63
    Nice example, but you gotta use a coroutine and use yields in your while loops.