void readCb(IAsyncResult ar) { try { Request request = (Request)ar.AsyncState; int nRead = request.read_stream.EndRead(ar); if (nRead > 0) { request.read_offset += nRead; request.read_stream.BeginRead(request.body.Array, request.read_offset, request.body.Count - request.read_offset, new AsyncCallback(readCb), request); } else { if (request.web_response == null) { FunDebug.LogError("Host manager response failed."); return; } webRequestCallback(request); request.read_stream.Close(); request.web_response.Close(); } } catch (Exception e) { if (e is ObjectDisposedException || e is NullReferenceException) { FunDebug.LogDebug("Dedicated server request operation has been cancelled."); } } }
void requestStreamCb(IAsyncResult ar) { try { Request request = (Request)ar.AsyncState; Stream stream = request.web_request.EndGetRequestStream(ar); ArraySegment <byte> body = request.body; if (body.Count > 0) { stream.Write(body.Array, 0, body.Count); } stream.Close(); IAsyncResult result = request.web_request.BeginGetResponse(new AsyncCallback(responseCb), request); ThreadPool.RegisterWaitForSingleObject( result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, heartbeat_seconds_ == 0 ? default_timeout_ : (int)(heartbeat_seconds_ / 2f) * 1000, true); } catch (Exception e) { WebException we = e as WebException; if (we != null && we.Status == WebExceptionStatus.ConnectFailure) { onRequestFailed((Request)ar.AsyncState); } else if ((we != null && we.Status == WebExceptionStatus.RequestCanceled) || (e is ObjectDisposedException || e is NullReferenceException)) { // When Stop is called HttpWebRequest.EndGetRequestStream may return an Exception FunDebug.LogDebug("Dedicated Server - Request operation has been cancelled."); } } }
void downloadFileCompleteCb(object sender, System.ComponentModel.AsyncCompletedEventArgs ar) { try { if (ar.Error != null) { throw ar.Error; } image_list_.RemoveAt(0); if (image_list_.Count > 0) { KeyValuePair <string, string> item = image_list_[0]; web_client_.DownloadFileAsync(new Uri(item.Key), item.Value); FunDebug.LogDebug("Announcement - Downloading image: {0}", item.Key); } else { FunDebug.Log("Announcement - All images have been downloaded.\npath:{0}", local_path_); onResult(AnnounceResult.kSucceeded); } } catch (Exception e) { FunDebug.LogError("Announcement - Failure in downloadFileCompleteCb:\n{0}", e.ToString()); onResult(AnnounceResult.kExceptionError); } }
public void LogDebug(string message, params object[] args) { #if ENABLE_LOG && ENABLE_DEBUG message = string.Format("[{0}] {1}", hash_, message); FunDebug.LogDebug(message, args); #endif }
void parseMessages() { lock (message_lock_) { while (true) { if (next_decoding_offset_ >= received_size_ - 4) { // Not enough bytes. Wait for more bytes to come. break; } int length = 0; if (BitConverter.IsLittleEndian) { byte[] bytes = new byte [4]; Buffer.BlockCopy(receive_buffer_, next_decoding_offset_, bytes, 0, 4); Array.Reverse(bytes); // gets big endian length = (int)BitConverter.ToUInt32(bytes, 0); } else { length = (int)BitConverter.ToUInt32(receive_buffer_, next_decoding_offset_); } if (length > 0) { int offset = next_decoding_offset_ + 4; if (received_size_ - offset < length) { // Need more bytes for a message body. Waiting. break; } object obj = FunapiDSRpcMessage.Deserialize(new ArraySegment <byte>(receive_buffer_, offset, length)); if (obj != null) { FunDedicatedServerRpcMessage msg = obj as FunDedicatedServerRpcMessage; messages_.Enqueue(msg); #if ENABLE_DEBUG StringBuilder log = new StringBuilder(); log.AppendFormat("[Peer:{0}] [S->C] type={1}, length={2} ", peer_id_, msg.type, length); FunapiDSRpcMessage.DebugString(msg, log); FunDebug.LogDebug(log.ToString()); #endif } next_decoding_offset_ = offset + length; } else { next_decoding_offset_ += 4; } } } }
void onSend() { try { lock (send_lock_) { if (send_queue_.Count <= 0 || sending_.Count > 0) { return; } Queue <FunDedicatedServerRpcMessage> list = send_queue_; send_queue_ = new Queue <FunDedicatedServerRpcMessage>(); foreach (FunDedicatedServerRpcMessage msg in list) { byte[] buf = FunapiDSRpcMessage.Serialize(msg); if (buf == null) { continue; } #if ENABLE_DEBUG StringBuilder log = new StringBuilder(); log.AppendFormat("[Peer:{0}] [C->S] type={1}, length={2} ", peer_id_, msg.type, buf.Length); FunapiDSRpcMessage.DebugString(msg, log); FunDebug.LogDebug(log.ToString()); #endif sending_.Add(new ArraySegment <byte>(buf)); } if (sending_.Count <= 0) { return; } lock (sock_lock_) { if (sock_ == null) { return; } sock_.BeginSend(sending_, SocketFlags.None, new AsyncCallback(this.sendCb), this); } } } catch (Exception e) { logWarning("Sending failed. {0}", e.ToString()); onDisconnect(PeerEventType.kDisconnected); } }
IEnumerator sendHeartbeat() { yield return(new WaitForSeconds(heartbeat_seconds_)); while (isActive) { FunDebug.LogDebug("Send a heart beat to host manager."); httpPost("heartbeat"); yield return(new WaitForSeconds(heartbeat_seconds_)); } }
void loadCachedList() { cached_list_.Clear(); string path = target_path_ + kCachedFileName; if (!File.Exists(path)) { return; } StreamReader stream = File.OpenText(path); string data = stream.ReadToEnd(); stream.Close(); if (data.Length <= 0) { FunDebug.LogWarning("Downloader.loadCachedList - Failed to load a cached file list."); return; } Dictionary <string, object> json = Json.Deserialize(data) as Dictionary <string, object>; List <object> list = json["list"] as List <object>; foreach (Dictionary <string, object> node in list) { DownloadFileInfo info = new DownloadFileInfo(); info.path = node["path"] as string; info.size = Convert.ToUInt32(node["size"]); info.hash = node["hash"] as string; if (node.ContainsKey("front")) { info.hash_front = node["front"] as string; } else { info.hash_front = ""; } cached_list_.Add(info); } FunDebug.LogDebug("[Downloader] Cached list loaded : {0}", cached_list_.Count); }
void deleteLocalFiles() { if (delete_file_list_.Count <= 0) { return; } FunDebug.Log("[Downloader] Try to delete {0} local files.", delete_file_list_.Count); foreach (string path in delete_file_list_) { if (File.Exists(path)) { File.Delete(path); FunDebug.LogDebug("'{0}' file deleted.\npath: {1}", Path.GetFileName(path), path); } } delete_file_list_.Clear(); }
void updateCachedList() { StringBuilder data = new StringBuilder(); data.Append("{ \"list\": [ "); int index = 0; foreach (DownloadFileInfo info in cached_list_) { data.AppendFormat("{{ \"path\":\"{0}\", ", info.path); data.AppendFormat("\"size\":{0}, ", info.size); if (info.hash_front.Length > 0) { data.AppendFormat("\"front\":\"{0}\", ", info.hash_front); } data.AppendFormat("\"hash\":\"{0}\" }}", info.hash); if (++index < cached_list_.Count) { data.Append(", "); } } data.Append(" ] }"); string path = target_path_ + kCachedFileName; FileStream file = File.Open(path, FileMode.Create); StreamWriter stream = new StreamWriter(file); stream.Write(data.ToString()); stream.Flush(); stream.Close(); FunDebug.LogDebug("[Downloader] Updates cached list : {0}", cached_list_.Count); }
void responseCb(IAsyncResult ar) { try { Request request = (Request)ar.AsyncState; if (request.was_aborted) { FunDebug.Log("Dedicated Server - Response callback. Request aborted."); return; } request.web_response = (HttpWebResponse)request.web_request.EndGetResponse(ar); request.web_request = null; if (request.web_response.StatusCode == HttpStatusCode.OK) { byte[] header = request.web_response.Headers.ToByteArray(); string str_header = System.Text.Encoding.ASCII.GetString(header, 0, header.Length); string[] lines = str_header.Replace("\r", "").Split('\n'); int length = 0; foreach (string n in lines) { if (n.Length > 0) { string[] tuple = n.Split(kHeaderSeparator, StringSplitOptions.RemoveEmptyEntries); string key = tuple[0].ToLower(); if (key == "content-length" && tuple.Length >= 2) { length = Convert.ToInt32(tuple[1]); break; } } } byte[] buffer = new byte[length]; request.body = new ArraySegment <byte>(buffer); request.read_stream = request.web_response.GetResponseStream(); request.read_stream.BeginRead(buffer, 0, length, new AsyncCallback(readCb), request); } else { FunDebug.LogError("Host manager response failed. status:{0}", request.web_response.StatusDescription); } } catch (Exception e) { WebException we = e as WebException; if (we != null && we.Status == WebExceptionStatus.ConnectFailure) { onRequestFailed((Request)ar.AsyncState); } else if ((we != null && we.Status == WebExceptionStatus.RequestCanceled) || (e is ObjectDisposedException || e is NullReferenceException)) { // When Stop is called HttpWebRequest.EndGetResponse may return a Exception FunDebug.LogDebug("Dedicated server request operation has been cancelled."); } } }
void httpPostSync(string command, string data, Action <object> callback = null) // for send version only { string url = server_url_ + command; // Request HttpWebRequest web_request = (HttpWebRequest)WebRequest.Create(url); web_request.Method = "POST"; web_request.ContentType = "application/octet-stream"; Request request = new Request(); request.web_request = web_request; request.callback = callback; request.command = command; try { byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data); ArraySegment <byte> body = new ArraySegment <byte>(bytes); web_request.ContentLength = body.Count; request.body = body; Stream stream = web_request.GetRequestStream(); stream.Write(request.body.Array, 0, request.body.Count); stream.Close(); request.web_response = (HttpWebResponse)web_request.GetResponse(); request.web_request = null; if (request.web_response.StatusCode == HttpStatusCode.OK) { request.read_stream = request.web_response.GetResponseStream(); StreamReader sr = new StreamReader(request.read_stream); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(sr.ReadToEnd()); request.body = new ArraySegment <byte>(buffer); webRequestCallback(request); request.read_stream.Close(); request.web_response.Close(); } else { FunDebug.LogError("Host manager response failed. status:{0}", request.web_response.StatusDescription); } } catch (Exception e) { WebException we = e as WebException; if (we != null && we.Status == WebExceptionStatus.ConnectFailure) { onRequestFailed(request); } else if ((we != null && we.Status == WebExceptionStatus.RequestCanceled) || (e is ObjectDisposedException || e is NullReferenceException)) { FunDebug.LogDebug("Dedicated Server - httpPostServerVersionSync operation has been cancelled."); } } }
void logDebug(string format, params object[] args) { FunDebug.LogDebug(makeLogText(format, args)); }
void downloadDataCompleteCb(object sender, DownloadDataCompletedEventArgs ar) { try { if (ar.Error != null) { throw ar.Error; } // Parse json string data = Encoding.UTF8.GetString(ar.Result); Dictionary <string, object> json = Json.Deserialize(data) as Dictionary <string, object>; if (json == null) { FunDebug.LogWarning("Announcement - Deserialize json failed. json: {0}", data); onResult(AnnounceResult.kInvalidJson); return; } FunDebug.Assert(json.ContainsKey("list")); List <object> list = json["list"] as List <object>; if (list == null || list.Count <= 0) { if (list == null) { FunDebug.LogWarning("Announcement - Announcement list is null."); } else if (list.Count <= 0) { FunDebug.LogWarning("Announcement - There is no announcement list."); } onResult(AnnounceResult.kListIsNullOrEmpty); return; } announce_list_.Clear(); foreach (Dictionary <string, object> node in list) { announce_list_.Add(node); // download image if (node.ContainsKey(kImageUrlKey) && node.ContainsKey(kImageMd5Key)) { checkDownloadImage(node[kImageUrlKey] as string, node[kImageMd5Key] as string); } if (node.ContainsKey(kExtraImagesKey)) { List <object> extra_images = node[kExtraImagesKey] as List <object>; foreach (Dictionary <string, object> extra_image in extra_images) { if (extra_image.ContainsKey(kExtraImageUrlKey) && extra_image.ContainsKey(kExtraImageMd5Key)) { checkDownloadImage(extra_image[kExtraImageUrlKey] as string, extra_image[kExtraImageMd5Key] as string); } } } } FunDebug.Log("Announcement - List has been updated. total: {0}", announce_list_.Count); if (image_list_.Count > 0) { // Request a file. KeyValuePair <string, string> item = image_list_[0]; web_client_.DownloadFileAsync(new Uri(item.Key), item.Value); FunDebug.LogDebug("Download announcement image: {0}", item.Key); } else { onResult(AnnounceResult.kSucceeded); } } catch (Exception e) { FunDebug.LogError("Failure in Announcement.downloadDataCompleteCb:\n{0}", e.ToString()); onResult(AnnounceResult.kExceptionError); } }
// Downloading files. void downloadResourceFile() { if (state_ != State.Downloading) { return; } if (download_list_.Count <= 0 || (partial_downloading_ && partial_download_list_.Count <= 0)) { updateCachedList(); download_time_.Stop(); FunDebug.Log("[Downloader] Took {0:F2}s for downloading all files.", download_time_.ElapsedMilliseconds / 1000f); if (partial_downloading_) { if (download_list_.Count > 0) { state_ = State.Ready; } else { state_ = State.Completed; } partial_downloading_ = false; FunDebug.Log("[Downloader] Partial downloading completed."); } else { state_ = State.Completed; FunDebug.Log("[Downloader] Download completed."); } onFinished(DownloadResult.SUCCESS); } else { DownloadFileInfo info = null; if (partial_downloading_) { info = partial_download_list_[0]; } else { info = download_list_[0]; } // Check directory string path = target_path_; int offset = info.path.LastIndexOf('/'); if (offset > 0) { path += info.path.Substring(0, offset); } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string file_path = target_path_ + info.path; if (File.Exists(file_path)) { File.Delete(file_path); } // Requests a file. string request_url = host_url_ + info.path; FunDebug.LogDebug("Download a file - {0}\nSave to {1}\n", request_url, file_path); cur_download_path_ = Path.GetDirectoryName(file_path); cur_download_path_ += "/" + Path.GetRandomFileName(); web_client_.DownloadFileAsync(new Uri(request_url), cur_download_path_, info); } }
// Checks download file list IEnumerator checkFileList(List <DownloadFileInfo> list) { List <DownloadFileInfo> tmp_list = new List <DownloadFileInfo>(list); List <string> verify_file_list = new List <string>(); List <string> remove_list = new List <string>(); Queue <int> rnd_list = new Queue <int>(); bool verify_success = true; int rnd_index = -1; DateTime cached_time = File.GetLastWriteTime(target_path_ + kCachedFileName); Stopwatch elapsed_time = new Stopwatch(); elapsed_time.Start(); delete_file_list_.Clear(); // Randomly check list if (cached_list_.Count > 0) { int max_count = cached_list_.Count; int count = Math.Min(Math.Max(1, max_count / 10), 10); System.Random rnd = new System.Random((int)DateTime.Now.Ticks); while (rnd_list.Count < count) { rnd_index = rnd.Next(1, max_count + 1) - 1; if (!rnd_list.Contains(rnd_index)) { rnd_list.Enqueue(rnd_index); } } FunDebug.LogDebug("[Downloader] {0} files are randomly selected for check.", rnd_list.Count); rnd_index = rnd_list.Count > 0 ? rnd_list.Dequeue() : -1; } // Checks local files int index = 0; foreach (DownloadFileInfo file in cached_list_) { DownloadFileInfo item = list.Find(i => i.path == file.path); if (item != null) { string path = target_path_ + file.path; FileInfo info = new FileInfo(path); if (!File.Exists(path) || item.size != info.Length || item.hash != file.hash) { remove_list.Add(file.path); FunDebug.LogWarning("'{0}' file has been changed or deleted.", file.path); } else { string filename = Path.GetFileName(item.path); if (filename[0] == '_' || index == rnd_index || File.GetLastWriteTime(path).Ticks > cached_time.Ticks) { if (index == rnd_index) { rnd_index = rnd_list.Count > 0 ? rnd_list.Dequeue() : -1; } verify_file_list.Add(file.path); StartCoroutine(MD5Async.Compute(path, item, delegate(string p, DownloadFileInfo f, bool is_match) { if (VerifyCallback != null) { VerifyCallback(p); } verify_file_list.Remove(f.path); if (is_match) { list.Remove(f); } else { remove_list.Add(f.path); verify_success = false; } } )); } else { list.Remove(item); } } } else { remove_list.Add(file.path); } ++index; } while (verify_file_list.Count > 0) { yield return(new SleepForSeconds(0.1f)); } removeCachedList(remove_list); FunDebug.LogDebug("[Downloader] Random validation has {0}", (verify_success ? "succeeded" : "failed")); // Checks all local files if (!verify_success) { foreach (DownloadFileInfo file in cached_list_) { DownloadFileInfo item = tmp_list.Find(i => i.path == file.path); if (item != null) { verify_file_list.Add(file.path); string path = target_path_ + file.path; StartCoroutine(MD5Async.Compute(path, item, delegate(string p, DownloadFileInfo f, bool is_match) { if (VerifyCallback != null) { VerifyCallback(p); } verify_file_list.Remove(f.path); if (!is_match) { remove_list.Add(f.path); if (!list.Contains(f)) { list.Add(f); } } } )); } } while (verify_file_list.Count > 0) { yield return(new SleepForSeconds(0.1f)); } removeCachedList(remove_list); } elapsed_time.Stop(); FunDebug.Log("[Downloader] Took {0:F2}s to check local files.", elapsed_time.ElapsedMilliseconds / 1000f); total_download_count_ = list.Count; foreach (DownloadFileInfo item in list) { total_download_size_ += item.size; } // Deletes files deleteLocalFiles(); if (total_download_count_ > 0) { state_ = State.Ready; event_.Add(delegate { FunDebug.Log("[Downloader] Ready to download."); if (ReadyCallback != null) { ReadyCallback(total_download_count_, total_download_size_); } }); } else { updateCachedList(); state_ = State.Completed; FunDebug.Log("[Downloader] All resources are up to date."); onFinished(DownloadResult.SUCCESS); } }