public override async Task <int> ReadAsync(byte[] buffer, int _offset, int count, CancellationToken cancellationToken) { if (length == 0) { return(0); } var pos = Position; await _readSem.WaitAsync().ConfigureAwait(false); try { var seg = cachedMeta ?? await engine.DownloadMetaForPath(path).ConfigureAwait(false); if (seg == null) { throw new FileNotFoundException(); } cachedMeta = seg; Int64 len = Length; long size = count; long offset = _offset + pos; Console.WriteLine("offset: {0}, count: {1}, path: {2}", offset, count, path); if (offset < len) { if (offset + size > len) { size = len - offset; } var read = (long)0; int extraBlockCounter = 4; // MAYBE: make concurrent and cap concurrency? or look ahead foreach (var c in seg.Commands .Where(c => c.CMD == MetaSegment.Command.CMDV.ADD) .Where(c => c.TYPE == MetaSegment.Command.TYPEV.BLOCK) .Select(c => c.FILE_ORIGIN) .SkipWhile(c => c.Start + c.Size <= offset) ) { if (read >= size || c.Start >= offset + size) { if (extraBlockCounter == 0) { break; } extraBlockCounter--; _ = engine.DownloadChunk(engine.Generator.GenerateRawOrParityID(c.Hash)); continue; } var mspos1 = read; var offset1 = (int)Math.Max(0, (offset + read) - c.Start); var size1 = (int)Math.Min(c.Size - offset1, size - read); if (size1 < 0) { throw new Exception("size1 < 0"); } read += size1; var data = await engine.DownloadChunk(engine.Generator.GenerateRawOrParityID(c.Hash)).ConfigureAwait(false); Array.Copy(data, offset1, buffer, mspos1, size1); } Position += read; return((int)read); } else { return(0); } } finally { _readSem.Release(); } }
public async Task <IActionResult> Index() { var engine = Program.BinsyncEngine; var route = getNormalizedRoute(); var path = getBinsyncPathFromNormalizedRoute(route); var m = await engine.DownloadMetaForPath(path); if (m == null) { // handle empty dir & file var prev = path.Split('/').SkipLast(1).Aggregate("", (a, b) => a + "/" + b).Trim('/'); var cur = path.Split('/').Last().Trim('/'); if (cur == "" && prev == "") { m = new Engine.Meta { IsFile = false, Path = "", Commands = new List <MetaSegment.Command>() }; } else { var p = await engine.DownloadMetaForPath(prev); if (p == null) { return(NotFound()); } MetaSegment.Command cmd; if ((cmd = p.Commands?.Where(c => c.FOLDER_ORIGIN?.Name == cur).Take(1).FirstOrDefault()) != null) { m = new Engine.Meta { IsFile = cmd.TYPE == MetaSegment.Command.TYPEV.FILE, Path = path, Commands = new List <MetaSegment.Command>() } } ; else { return(NotFound()); } } } if (m.IsFile) { return(Redirect(escape($"/_dav/{m.Path}"))); } var entries = new List <entry>(); if (path != "") { entries.Add(new entry { href = escape(route.Split('/').SkipLast(1).Aggregate("", (a, b) => a + "/" + b).Substring(1)), label = "..", @class = "back", title = "Back", }); } entries.AddRange(m.Commands.Select(c => new { c, f = c.TYPE == MetaSegment.Command.TYPEV.FILE }).Select(x => new entry { href = escape(x.f ? $"/_dav/{m.Path}/{x.c.FOLDER_ORIGIN?.Name}".Replace("//", "/") : $"{route}/{x.c.FOLDER_ORIGIN?.Name}"), label = x.c.FOLDER_ORIGIN?.Name, @class = x.f ? "file" : "folder", title = x.f ? $"File: {x.c.FOLDER_ORIGIN?.FileSize} B" : "Folder", })); var pubHash = engine.PublicHash.Substring(0, 8); var text = $"<font color=\"gray\">[{HttpUtility.HtmlEncode(pubHash)}]</font> /" + HttpUtility.HtmlEncode(m.Path); var elems = entries .Select(e => $"<a href=\"{e.href}\"><li class=\"{e.@class}\" title=\"{e.@title}\">{HttpUtility.HtmlEncode(e.label)}</li></a>") .ToList(); if (path == "" && entries.Count == 0 || elems.Count == 1) { elems.Add("<li class=\"empty\">This folder is empty.</li>"); } var webDavUrl = $"{Request.Scheme}://{Request.Host}" + escape($"/_dav/{m.Path}".TrimEnd('/')); var title = HttpUtility.HtmlEncode($"binsync [{pubHash}]"); Response.ContentType = "text/html; charset=UTF-8"; return(Content($@" <!DOCTYPE html> <html> <head> <meta charset=""UTF-8""> <title>{title}</title> <style> a:link {{ text-decoration: none; }} a:hover {{ text-decoration: underline; }} li {{ list-style: none; }} .empty {{ color: gray; }} li::before {{ display:inline-block; }} .empty::before {{ content: ""ℹ️ ""; }} .back::before {{ content: ""⬅️ ""; }} .folder::before {{ content: ""📁 ""; }} .file::before {{ content: ""📄 ""; }} </style> </head> <body> <a title=""Home"" href=""/""> <img height=""32px"" alt=""binsync logo"" src=""/images/header_logo.png""> </a> <hr> <h3>{text}</h3> <ul> {elems.Aggregate("", (a, b) => $"{a}\n\t\t\t{b}").Trim('\n').TrimStart('\t')} </ul> <hr> WebDAV: {webDavUrl} </body> </html> " )); // todo: learn some asp net }