public static (FileDescriptor, List <byte[]>) FromFile(Stream file, string name, int chunk_size = 65000) { var pieces = new List <byte[]>(); var hasher = HashSingleton.Duplicate(); var descriptor = new FileDescriptor() { Name = name, Length = file.Length, Created = DateTime.UtcNow, Checksum = new byte[hasher.HashSize / 8], PieceIdentifiers = new List <byte[]>(), MimeType = MimeMapper.MapToMime(name) }; byte[] buffer = new byte[chunk_size]; while (file.Position < file.Length) { var read = file.Read(buffer, 0, chunk_size); var chunk = new byte[read]; Array.Copy(buffer, 0, chunk, 0, read); if (file.Position == file.Length) { hasher.TransformFinalBlock(buffer, 0, read); } else { hasher.TransformBlock(buffer, 0, read, buffer, 0); } pieces.Add(chunk); descriptor.PieceIdentifiers.Add(HashSingleton.Compute(chunk)); } descriptor.Checksum = hasher.Hash; return(descriptor, pieces); }
public HarmonyModule() { Get("/health", _ => { if (Node == null) { return(Response.AsJson(new { Running = false })); } try { return(Response.AsJson(new { Running = Node.Running, Uptime = (long)(DateTime.Now - Start).TotalMilliseconds, Stable = Node.Stable, ListenEndPoint = Node.ListenEndPoint.ToString(), id = Node.ID.ToUsefulString(), Successor = Node.Successor.ToUsefulString(), Predecessor = Node.Predecessor.ToUsefulString(), PeerCount = Node.Network.PeerCount, Connections = Node.Network.Nodes.Values.OfType <RemoteNode>() .Select(n => new { id = n.ID.ToUsefulString(), ep = n.RemoteEndPoint?.ToString(), alive = n.Ping() }), CandidatePeers = Node.Network.GetCandidatePeers().Count(), KeysInMemory = Node.LocalDataStore.Pieces.Values .Where(piece => piece != null) .Select(piece => new { id = piece.OriginalID.ToUsefulString(), d = piece.RedundancyIndex, IteratedID = piece.ID.ToUsefulString(), Contents = $"{piece.Data.ToUsefulString(true)} ({piece.Data.Length} bytes)", ContentsText = piece.Data.Length > 50 ? "(too long)" : Encoding.UTF8.GetString(piece.Data), Source = piece.Source.ToUsefulString() }) })); } catch (Exception ex) { return(CreateError($"{ex.GetType()} occurred while generating health page: {ex.Message}", HttpStatusCode.InternalServerError)); } }); Get("/file", _ => { if (Node == null || !Node.Running) { return(CreateError("Node is down", HttpStatusCode.ServiceUnavailable)); } var id_str = ""; id_str = Request.Query["id"] ?? ""; if (id_str.Length != Node.KeySize * 2 || !Utilities.TryParseBytesFromString(id_str, out byte[] descriptor_piece_id)) { return(CreateError("Invalid piece ID")); } var descriptor_piece = Node.RetrievePiece(descriptor_piece_id); if (descriptor_piece == null) { return(CreateError($"Failed to retrieve descriptor piece")); } var descriptor = FileDescriptor.Deserialize(descriptor_piece.Data); var pieces = descriptor.PieceIdentifiers.Select(piece_id => Node.RetrievePiece(piece_id)); if (pieces.Any(p => p == null)) { return(CreateError($"Failed to retrieve {pieces.Count(p => p == null)} pieces out of {descriptor.PieceIdentifiers.Count}")); } var descriptor_mime_type = descriptor.MimeType; var whitelisted_mime_types = new[] { "image/*", "audio/*", "video/*", "font/*", "model/*", "text/plain", "text/csv", "application/pdf", "application/octet-stream" }; if (!whitelisted_mime_types.Any(allowed_type => MimeMapper.WildcardMatch(allowed_type, descriptor_mime_type))) { descriptor_mime_type = "application/octet-stream"; } return(new Response() { Contents = (str) => { foreach (var piece in pieces) { str.Write(piece.Data, 0, piece.Data.Length); } str.Flush(); }, ContentType = descriptor_mime_type, StatusCode = HttpStatusCode.OK }); });