//unity www的设计是:new出来的瞬间,请求就立即发起了 //由于排队的需求,只能推迟new的时机 private void BeginRequest(WWWRequest req) { WWW www = null; switch (req.Type) { case RequestType.Login: www = new WWW(req.Url, req.Data); break; case RequestType.Get: www = new WWW(req.Url, null, req.Headers); break; case RequestType.Post: www = new WWW(req.Url, req.Data, req.Headers); break; default: InfoTips.LogWarning("undefined type: " + req.Type.ToString()); break; } req.RawWWW = www; req.StartTime = DateTime.Now; sendingRequests.Add(requestIdGen++, req); }
public void Post(string resource, string jsonString, OnHttpResponse callback) { var fullURL = GetHttpPrefix() + resource; var headers = GetAuthHeader(); headers.Add("Content-Type", "application/json"); var postJson = jsonString;//.ToString(); InfoTips.LogInfo("[HttpPost] " + fullURL); InfoTips.LogInfo("postJson:" + postJson + "--Headers:" + headers); var formData = Encoding.UTF8.GetBytes(jsonString); var req = new WWWRequest() { Data = formData, Headers = headers, RespCallback = RespWrapper(callback), Type = RequestType.Post, Url = fullURL }; waitingRequests.Enqueue(req); }
private static byte[] GetMultipartFormData(Dictionary <string, object> postParameters, string boundary) { Stream formDataStream = new System.IO.MemoryStream(); bool needsCLRF = false; foreach (var param in postParameters) { // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. // Skip it on the first parameter, add it to subsequent parameters. if (needsCLRF) { formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); } needsCLRF = true; if (param.Value is FileParameter) { FileParameter fileToUpload = (FileParameter)param.Value; // Add just the first part of this param, since we will write the file data directly to the Stream string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream"); //UnityEngine.InfoTips.LogInfo(header); formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); // Write the file data directly to the Stream, rather than serializing it to a string. formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); } else { string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value); formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); } } // Add the end of the request. Start with a newline string footer = "\r\n--" + boundary + "--\r\n"; formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); // Dump the Stream into a byte[] formDataStream.Position = 0; byte[] formData = new byte[formDataStream.Length]; formDataStream.Read(formData, 0, formData.Length); formDataStream.Close(); InfoTips.LogInfo(Encoding.UTF8.GetString(formData) + ""); return(formData); }
private void LoadNext() { var mat = toLoadMats[0]; var matCopy = mat; InfoTips.LogInfo("材质AB包URL:" + mat.url); HttpGetAb(mat.url, ab => { StartCoroutine(LoadProceduralMaterial(ab, matCopy, null)); }); }
/// <summary> /// cache item /// </summary> /// <param name="matName"></param> /// <returns></returns> public MatCacheItem GetByName(string matName) { if (items.ContainsKey(matName)) { return(items[matName]); } else { InfoTips.LogWarning("找不到该材质:" + matName); return(null); } }
/// <summary> /// info /// </summary> /// <param name="tagName"></param> /// <returns></returns> public List <MatCacheItem> GetByTag(string tagName) { if (itemsByTag.ContainsKey(tagName)) { return(itemsByTag[tagName]); } else { InfoTips.LogWarning("找不到该材质:" + tagName); return(null); } }
public void RemoveCache() { var allCacheFiles = Directory.GetFiles(CacheFolder); var count = 0; foreach (var file in allCacheFiles) { File.Delete(file); count++; } InfoTips.LogInfo("[Http] Remove total:" + count.ToString() + " cache files"); }
/// <summary> /// load单个材质,保证每个回调都必然被调用 /// </summary> public void LoadMat(string matName, Action <MatCacheItem> callback) { if (items.ContainsKey(matName)) { callback(items[matName]); return; } //幸好不是真正的多线程 if (loadCallbacksCache.ContainsKey(matName)) { loadCallbacksCache[matName].Add(callback); return; } var found = false; foreach (var item in AllMatInfo) { if (item.name == matName) { found = true; HttpGetAb(item.url, ab => { StartCoroutine(LoadProceduralMaterial(ab, item, cacheItem => { var callbackList = loadCallbacksCache[matName]; foreach (var cb in callbackList) { cb(cacheItem); } })); }); loadCallbacksCache.Add(matName, new List <Action <MatCacheItem> >() { callback }); break; } } if (!found) { InfoTips.LogWarning(matName + "not found"); callback(null); } }
//需要解json private HttpResp GenerateResp(WWW www) { if (www == null) { return(GenTimeoutResp()); } var resp = new HttpResp(); if (!string.IsNullOrEmpty(www.error)) { resp.Error = HttpResp.ErrorType.NetworkError; resp.ErrorText = www.error; } else { try { var respJson = JsonUtility.FromJson <JsonBase>(www.text); if (respJson.error == EXPIRED_ERROR) { resp.Error = HttpResp.ErrorType.AccessExpired; resp.ErrorText = resp.Error.ToString(); } else if (!string.IsNullOrEmpty(respJson.error)) { resp.Error = HttpResp.ErrorType.LogicError; resp.ErrorText = respJson.error; } else { resp.Error = HttpResp.ErrorType.None; } } catch (Exception e) { InfoTips.LogWarning("parse json error: " + e.ToString()); resp.Error = HttpResp.ErrorType.JsonError; resp.ErrorText = e.ToString(); } } resp.WwwText = www.text; return(resp); }
/// <summary> /// 普通get /// </summary> public void Get(string resource, NameValueCollection query, OnHttpResponse callback) { var fullURL = GetHttpPrefix() + resource + QueryToString(query); InfoTips.LogInfo("[HttpGet] " + fullURL); var req = new WWWRequest() { Data = null, Headers = GetAuthHeader(), RespCallback = RespWrapper(callback), Type = RequestType.Get, Url = fullURL }; waitingRequests.Enqueue(req); }
private void GetRaw(string resource, NameValueCollection query, Action <WWW> callback) { var fullURL = resource + QueryToString(query); InfoTips.LogInfo("[HttpPrivateGet] " + fullURL); var req = new WWWRequest() { Data = null, Headers = GetAuthHeader(), RespCallback = callback, Type = RequestType.Get, Url = fullURL }; waitingRequests.Enqueue(req); }
private void HttpGetAb(string url, Action <AssetBundle> callback) { WWWManager.Instance.GetFile(url, LocalCacheEntry.CacheType.AssetBundle, (resp, entry) => { if (resp.Error != HttpResp.ErrorType.None) { if (OnLoadError != null) { OnLoadError(url); } InfoTips.LogWarning("Get Material AssetBundle Error: " + resp.ToString()); } else { callback(entry.AB); } }); }
private void HttpGetAllMats(Action <List <MaterialInfo> > callback, string tags = "") { WWWManager.Instance.Get("meterials/search", new NameValueCollection() { { "tags", tags } }, resp => { if (resp.Error != HttpResp.ErrorType.None) { if (OnLoadError != null) { OnLoadError(""); } InfoTips.LogWarning("Get Material Error: " + resp.ToString()); } else { var mats = JsonUtility.FromJson <MaterialInfoCollection>(resp.WwwText); callback(mats.data); } }); }
/// <summary> /// 带本地缓存的http文件获取 /// 本地版本实际上是同步,网络版本是异步</summary> /// <param name="url"></param> /// <param name="type"></param> /// <param name="callback"></param> /// <param name="fromQY">是否是从青云服务器上下载,区别于:百度API获取街景</param> public void GetFile(string url, LocalCacheEntry.CacheType type, OnHttpGetFileResponse callback, bool fromQY = true) { if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException("Attempt to getfile from an empty URL"); } // 文件缓存之后的文件名 var local = URLToLocalPath(url); InfoTips.LogInfo("[GetFile] related local path:" + local); // 缓存中已经存在 if (File.Exists(local)) { InfoTips.LogInfo("[GetFile] load from local"); var fakeResp = new HttpResp(); fakeResp.Error = HttpResp.ErrorType.None; fakeResp.WwwText = ""; switch (type) { case LocalCacheEntry.CacheType.Texture: var tex = new Texture2D(2, 2); var imgBytes = File.ReadAllBytes(local); tex.LoadImage(imgBytes); callback(fakeResp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Texture, Texture = tex }); break; case LocalCacheEntry.CacheType.Fbx: callback(fakeResp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Fbx, FbxPath = local }); break; case LocalCacheEntry.CacheType.AssetBundle: var ab = AssetBundle.LoadFromFile(local); callback(fakeResp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.AssetBundle, AB = ab }); break; case LocalCacheEntry.CacheType.Raw: var bytes = File.ReadAllBytes(local); callback(fakeResp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Raw, Bytes = bytes }); break; default: break; } } else { InfoTips.LogInfo("[GetFile] load from remote"); string realUrl; NameValueCollection query; if (fromQY) { realUrl = GetHttpPrefix() + "entities/download"; query = new NameValueCollection() { { "path", url } }; } else { realUrl = url; query = null; } GetRaw(realUrl, query, www => { var resp = GenerateGetfileResp(www); if (resp.Error != HttpResp.ErrorType.None) { callback(resp, null); } else { //write cache //TODO: more scientific way: async var localPath = URLToLocalPath(url); if (localPath.Length > 250) { throw new IOException("localpath length overflowwww!!!"); } File.WriteAllBytes(localPath, www.bytes); switch (type) { case LocalCacheEntry.CacheType.Texture: callback(resp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Texture, Texture = www.texture }); break; case LocalCacheEntry.CacheType.Fbx: callback(resp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Fbx, FbxPath = localPath }); break; case LocalCacheEntry.CacheType.AssetBundle: callback(resp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.AssetBundle, AB = www.assetBundle }); break; case LocalCacheEntry.CacheType.Raw: callback(resp, new LocalCacheEntry() { Type = LocalCacheEntry.CacheType.Raw, Bytes = www.bytes }); break; default: break; } } }); } }
private IEnumerator LoadProceduralMaterial(AssetBundle ab, MaterialInfo matInfo, Action <MatCacheItem> loadDone) { if (ab == null) { yield break; } var pm = ab.LoadAllAssets <ProceduralMaterial>()[0]; if (!pm.isProcessing && autoRebuild) { pm.RebuildTextures(); } while (pm.isProcessing) { yield return(new WaitForEndOfFrame()); } InfoTips.LogInfo(pm.name + " material build done"); // previewer.gameObject.SetActive(true); var item = new MatCacheItem(); item.MatName = matInfo.name; item.Info = matInfo; item.Material = pm; item.Loaded = true; items.Add(item.MatName, item); //cache mat items by tag foreach (var tag in matInfo.Tags) { if (itemsByTag.ContainsKey(tag)) { itemsByTag[tag].Add(item); } else { itemsByTag.Add(tag, new List <MatCacheItem>() { item }); } } // previewer.gameObject.SetActive(false); //可能单个加载 if (toLoadMats.Contains(matInfo)) { toLoadMats.Remove(matInfo); } if (loadDone != null) { loadDone(item); } if (toLoadMats.Count > 0) { LoadNext(); } else { // Debug.Log("load done ----------------------------------------------------------"); } }
/// <summary> /// 网络请求发动机 /// </summary> /// <returns></returns> private IEnumerator MainLoop() { while (true) { yield return(new WaitForEndOfFrame()); var now = DateTime.Now; //handle response if (sendingRequests.Count > 0) { // 已经发起过的RawWWW var disposableKeys = new List <int>(); foreach (var key in sendingRequests.Keys) { var sendingOne = sendingRequests[key]; var www = sendingOne.RawWWW; var isTimeout = false; if (!www.isDone) { var cost = (now - sendingOne.StartTime).TotalMilliseconds; //timeout if (cost > TimeOut * 1000) { sendingOne.RespCallback(null); isTimeout = true; InfoTips.LogInfo("Timeout cost: " + cost.ToString()); } else { // www没有下载完,也没超时,那就继续 continue; } } // www,没有完成,但是超时 if (!isTimeout) { if (www.error != null) { InfoTips.LogInfo(www.error); sendingOne.RespCallback(www); } else //not timeout & isdone { InfoTips.LogInfo("[HttpResp] " + www.text); sendingOne.RespCallback(www); } } // 既然能走到这里,说明www已经完成 www.Dispose(); disposableKeys.Add(key); } foreach (var key in disposableKeys) { sendingRequests.Remove(key); } } //do send var availableCount = concurrentLimit - sendingRequests.Count; // 当前发起请求数,没有超过阈值,从等待队列中选 if (availableCount > 0 && waitingRequests.Count > 0) { //one packet per frame var req = waitingRequests.Dequeue(); BeginRequest(req); } } }
void Awake() { IsOnlySaveOnePage = IsEnable = true; IsVisible = true; onlyOne = this; }