-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(drivers/mediafire): support concurrent upload #1366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(drivers/mediafire): support concurrent upload #1366
Conversation
|
We didn't know the MediaFire token expired so fast. You can consider reverting this part of the change, but please remember to stop the cron job in the |
7e49493 to
5d22bda
Compare
- Implement complete MediaFire storage driver with session token authentication - Support all core operations: List, Get, Link, Put, Copy, Move, Remove, Rename, MakeDir - Include thumbnail generation for media files - Handle MediaFire's resumable upload with intelligent and multi-unit transfers - Support concurrent chunk uploads using errgroup.NewOrderedGroupWithContext, using splitted file caching for large files - Optimize memory usage with adaptive buffer sizing (10MB-100MB (default)) - Include rate limiting and retry logic for API requests - Add proper error handling and progress reporting - Handle MediaFire's bitmap-based resumable upload protocol Closes PR OpenListTeam#1322
5d22bda to
d68b1da
Compare
Yeah, that happens because since MediaFire does not provide API_KEY nor APP support for new projects, basically we are using API, but without the "classical" auth. And... if OpenList server is running then MediaFire is constantly refreshing the token, but once server or device is shutdown, you have to configure session again, which is very disgusting, but this is how it goes, not even rclone has MediaFire support now, no more official dev support :( Ok, I'll revert cron code. |
- Implement complete MediaFire storage driver with session token authentication - Support all core operations: List, Get, Link, Put, Copy, Move, Remove, Rename, MakeDir - Include thumbnail generation for media files - Handle MediaFire's resumable upload with intelligent and multi-unit transfers - Support concurrent chunk uploads using errgroup.NewOrderedGroupWithContext, using splitted file caching for large files - Optimize memory usage with adaptive buffer sizing (10MB-100MB (default)) - Include rate limiting and retry logic for API requests - Add proper error handling and progress reporting - Handle MediaFire's bitmap-based resumable upload protocol - Implement automatic session token renewal Closes PR OpenListTeam#1322
217519a to
06abed9
Compare
|
@KirCute done, I followed threaded logic with chunks, without fully caching files. |
并不会,因为可以修改PR目标分支。目标基本分支已改为 |
|
@ILoveScratch2, yes, but once merged it mediafire branch, could be then merged into main. |
|
@Da3zKi7 Yep |
|
@ILoveScratch2 thank your for your work mate |
|
@Da3zKi7 You're welcome. Actually, you were the one who handled most of the APIs, and without your initial modifications, this wouldn't have been possible.. |
|
Yeah, some day, just for curiosity I tried to add MediaFire account to AList and figured out was not there. Then I saw your issue requesting the driver. And I did it, maybe bad code :) but actually working ))) You are always welcome! |
Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com>
|
Small files (< 10MB): Uses the MediaFire API's unitSize (typically 4MB) as the buffer. This may cause "stream not cached" errors with concurrent access since the buffer might be smaller than conf.MaxBufferLimit. That error already happened me! Medium files (10MB-100MB): Uses the entire file size as buffer, which triggers full file caching in NewStreamSectionReader, enabling concurrent chunk access. Large files (>100MB): Caps the buffer at 100MB to prevent excessive memory usage while still likely triggering the caching mechanism for concurrent access. For example, testing using max buffer limit: i.e. 1024MB If a large file is uploaded, i.e. 2GB, will exceed the avail buffer limit, also as @KirCute stated before fully caching a file is not a good practice, and obviously not a optimized way. Also, as I already told all, MediaFire resumable upload already manages chunks (yes, that endpoint is uploading each part of file and could be paused, and then resumed), so, What you did:
This fully caches the file, and for example a 1GB file will use 1GB in memory, and a file of 5GB need to be cached in temp storage, which is actually not optimization. Medium files (10MB-100MB): Uses full file size, triggering file.CacheFullAndWriter() since it exceeds typical unit sizes Large files (>100MB): Uses 100MB buffer, which exceeds i.e 1024MB (or whatever in your machine) MaxBufferLimit threshold, also triggering full caching Small files: Uses unit size for minimal memory footprint MediaFire commonly uses 4MB units, but it depends of how big the file is, and assuming it is an error. If you have Pro / Ultra plan you can upload up to 50GB files, obviously using 50GB in temp storage has no sense I know doing The intelligent buffer sizing approach is the best way because:
Ordered Group with Context: Creates multiple goroutines (up to d.UploadThreads, default 3) that can upload different chunks simultaneously Stream Section Reader: Uses intelligent buffer sizing to enable concurrent access to different file sections, forcing file caching when needed for large files This implements the most common upload in drivers, but remember, MediaFire resumable upload is actually uploading file chunks. The concurrent implementation processes multiple MediaFire upload units simultaneously (up to 3 threads by default), significantly improving upload performance compared to sequential processing of each unit one by one. So my aproach is using AList / OpenList threaded upload over MediaFire chunked upload For more context, please read MediaFire documentation. But for simplicity, a short paragraph: Definition: Resumes an upload that was interrupted. Upload a unit/chunk of a file as part of a resumable upload to the user's account. Uploading large files through upload/simple can take a long time, and if it fails, re-uploading the file starts from the beginning--unlike a resumable upload, which allows you to upload the file in small units or chunks. So if one unit fails to upload, only that unit is re-uploaded. upload/resumable can only be called after a call to upload/check which initiates the resumable upload. This API returns the upload key when successful. After you upload all the units, you can pass the key to upload/poll_upload to get the quickkey. Please refer to the documentation about the API upload/poll_upload for more details. Here, is another proof why fully caching has no logic explanation. The upload need it in chunks, not the full file! |
|
/upload/check.php需要提供SHA256,而stream只能读取一次,在stream没携带SHA256时会触发缓存,这无法避免 OpenList/drivers/mediafire/driver.go Lines 359 to 368 in a0ebdcd
而stream.NewStreamSectionReader是为了某个块上传出错时可以重新读取而设计的,如果mediafire不需要,直接使用for+io.LimitReader最合适 |
Yes, but MediaFire's unitSize is only 4MB by default, so even for big files will never exceed the buffer. `` `` By default bufferSize = 4MB If file is bigger than 100MB, bufferSize is 100MB That means a 8MB file will use a 4MB buffer without problems, because MediaFire expects only 4MB chunk, not a 8MB chunk. If MediaFire determines that due the file is so big, for example 20MB for every unitSize, MediaFire will accept only 20MB chunks. Dynamic bufferSize approach is the solution:
Remember, unitSize logic is handled by MediaFire, not by the driver, once MediaFire defines unitSize is used in buffer logic. The fixed int(unitSize) approach works only for sequential uploads but fails with concurrent access patterns, the implemented upload is concurrent, not sequential! I really appreciate your suggestions, but this is the way MediaFire's API works. |
|
Also... When MediaFire's unitSize by default is 4MB and you use it directly as the buffer size, this creates several issues based on the OpenList caching logic. Since your system max buffer limit could be .i.e. 1024MB, the 4MB unitSize is much smaller than the MaxBufferLimit. This means: No file caching occurs - The condition maxBufferSize > conf.MaxBufferLimit (4MB > 1024MB) is false I have an example, that happened me while testing the upload... I experienced exactly this issue: Using int(unitSize) with 4MB caused "stream not cached: request offset 4194304 != current offset 0" MediaFire upload is concurrent, not sequential... that causes errors |
errgroup.Lifecycle的Before在errgroup.NewOrderedGroupWithContext是顺序执行的 OpenList/pkg/errgroup/errgroup.go Lines 55 to 63 in d465da4
OpenList/pkg/errgroup/errgroup.go Lines 32 to 36 in d465da4
OpenList/pkg/errgroup/errgroup.go Lines 65 to 108 in d465da4
按理说不会出现这种情况,请你重新测试 |
|
@ILoveScratch2 I am tired of this disgusting guy with god complex. Please do not take my work again, I'll only contribute to AList, this is only another fork. I have no time and I do not take a cent for coding drivers. So sorry, I will not support your needs anymore. If you need something, ask for it at AList repo. Open source is supposed to be collaborative, looks like a random guy is pretending to be the good and the best developer, I am really tired, he does not even know how MediaFire API works, I am the first guy how developed a driver, rclone does not even support MediaFire yet. So, keep acting as gods, and develop your own code without taking others job. I do not even see you commited a driver at AList, you are not AList experts, you did nothing for AList, just being disgusting and selfish people, instead of being thankful about what others code for free. Do not tag me anymore, I do not talk with selfish people @ILoveScratch2 MediaFire is already available at AList, leave this sh!t and disgusting people. Nobody is perfect, but at least I read all MediaFire documentation, and what you did apart of just treating others as dummies, ok gods, I need you code drivers and really commit to AList instead of trashy forks! Do not tag me here anymore! |
|
I am done here |
|
我只想说 I just want to point out that when unitSize is greater than bufferSize and the stream has no cache, GetSectionReader will panic. The Before events in errgroup.Lifecycle are executed sequentially in errgroup.NewOrderedGroupWithContext. If you're okay with Google Translate's machine translation, I can use it to translate the Chinese into English and then reply. |
https://github.com/AlistGo/alist/commits/main/?author=KirCute |
|
j2rong4cn never coded a driver, that was my point. You can criticize a lot others code, but, if you never developed an AList driver why being so mad. This is not about which codes better or who has more commits at AList or OpenList repos, is about why being hard with someone just tried to help! Anyway ILoveScratch2, if do you think my code is crap, I expect you never cherry-pick or fork what I do, for you I am just a dummy who codes trash. I also read a comment in another PR that "looks like I do not know what I do", okay, so just ignore the drivers I code at AList. I am not the best, I am not even good maybe, but at least I tried to help, especially when you opened issue at AList repo, but okay, everything I do is with good intentions to help a little. Best regards )) |
I opened issue in AList repo? Anyway, You may be partly right, we shouldn't get too much into the driving problem, it feels like we've gone a little too far |
I think you are right, too far. But I just needed you understand me, I explained and explained why even looks crazy, the code in that part had sense, due to the way MediaFire takes the chunks. But is okay, If you say is incorrect, is wrong... |
Nobody say your code is crap. @j2rong4cn kept asking questions simply because he didn't fully understand what you were saying. To be honest, I didn't completely grasp it either, even though I used a translation tool. @j2rong4cn developed nearly the entire Understanding how file streams should be properly handled is crucial, and we are all simply working towards ensuring the drivers function correctly, rather than competing to see who knows more about MediaFire. |
"looks like I do not know what I do" is what I said. However, this is an inaccurate translation of my original statement. What I actually said was that 'the original author did not seem sufficiently familiar with the AList source code'. I had solid reasons for making this judgment. For example, you returned an ObjThumb with an empty Thumbnail and an object with an unchanged Path after moving it—these are common mistakes often made by first-time drive contributors, and it does not mean that I completely dismiss your work. |
All in all, I hope you don’t interpret the discussion as one-sided criticism. In my view, j2rong4cn’s comments were more about confirming and inquiring why the code you wrote is correct, rather than unilaterally accusing you of writing it wrong. All the best. |
Hello, sorry. Seems the context was misinterpreted and is due to translation faults. I know you committed crucial and util things for AList, discredit your work was wrong. Instead of being stressed maybe I should appreciate you do not want to merge possible unstable code and having a strict quality control is not bad at all. Yes, I do not see this as competition, is not about who codes the best drivers or things, is about supporting a community and many people who does not have a GitHub account and is a "standard" user who downloaded OpenList, most people would never thank you for the driver, first of all because is not about fame, and because they do not know how to do it. |
There is no doubt @j2rong4cn supported AList, and I know he has a strong knowledge, I interpreted his comments as criticism instead of a suggestion or pure question because context or examples were not clear. I comprehend translation did not help us too! Yes, now I understand he was trying to ask me instead of pointing the code was wrong. Having a quality control is good |
That wrong translation changed all panorama. Yes, and I do not get offended by that statement. In fact MediaFire driver was my first commit and my first driver, also Golang is not my prior nor my favorite language, not even a language I have a solid experience. Yes, if you do not update path, thumb fails. Also I forgot to add cron shutdown in Drop() My code is not perfect and will never be the perfect code |
Got it, know I understand All the best |
|
If you consider it appropriate, you could merge it or not, I tried to explain why works, and I tested uploading really small, small, medium and also big files. I know you have worries about if the driver is working, but you could help me testing the driver, if you find is not working we could fix it |
438fc72 to
7081986
Compare
|
@ILoveScratch2 @j2rong4cn @KirCute If you felt disrespected, I offer an apologize for you. Despite what you decide, giving a sorry is always good :) |
Signed-off-by: D@' 3z K!7 <99719341+Da3zKi7@users.noreply.github.com>
|
I understand you, it doesn't matter much. |
Thank you, If you need something just ask me, I am not the best, but I always try to help. |
* feat(drivers): add MediaFire driver support (#9319) - Implement complete MediaFire storage driver - Add authentication via session_token and cookie - Support all core operations: List, Get, Link, Put, Copy, Move, Remove, Rename, MakeDir - Include thumbnail generation for media files - Handle MediaFire's resumable upload API with multi-unit transfers - Add proper error handling and progress reporting Co-authored-by: Da3zKi7 <da3zki7@duck.com> * fix(mediafire): fix code errors in mediafire * fix(mediafire): fix code errors in mediafire * fix(drivers): add session renewal cron for MediaFire driver (#9321) - Implement automatic session token renewal every 6-9 minutes - Add validation for required SessionToken and Cookie fields in Init - Handle session expiration by calling renewToken on validation failure - Prevent storage failures due to MediaFire session timeouts Fixes session closure issues that occur after server restarts or extended periods. Co-authored-by: Da3zKi7 <da3zki7@duck.com> * docs: restore README changes Signed-off-by: ILoveScratch <ilovescratch@foxmail.com> * fix * fix * fix: add stream upload limit * fix * fix: clear action token on drop and refactor header setting * feat(drivers/mediafire): optimize file caching - support direct stream processing - Remove forced caching to *os.File type - Support generic model.File interface for better flexibility - Improve upload efficiency by avoiding unnecessary file conversions - Fix return type to use model.Object instead of model.ObjThumb * feat(drivers/mediafire): improve global rate limiting - Ensure all API methods properly use context for rate limiting - Fix context parameter usage in getDirectDownloadLink, getActionToken, getFileByHash - Maintain consistent rate limiting across all MediaFire API calls * feat(drivers/mediafire): unify return types - remove unnecessary ObjThumb - Change MakeDir, Rename, Copy methods to return model.Object instead of model.ObjThumb - Remove empty Thumbnail fields where not meaningful - Keep ObjThumb only for fileToObj (List operations) which provides actual thumbnail URLs - Improve code consistency and reduce unnecessary wrapper objects * refactor(drivers/mediafire): extract common error handling logic - Add checkAPIResult helper function to reduce code duplication - Replace repetitive MediaFire API error checks with centralized function - Maintain specific error messages for unique cases (token, upload, search) - Improve code maintainability and consistency * enhance(drivers/mediafire): improve quick upload implementation - Add null check for existingFile to prevent potential issues - Improve error handling in quick upload - continue normal upload if search fails - Add detailed comments explaining quick upload logic - Optimize getExistingFileInfo with clearer fallback strategy - Ensure upload reliability even when file search encounters issues * refactor(drivers/mediafire): optimize request method reusability - Extract common HTTP request logic into apiRequest method - Reduce code duplication between getForm and postForm methods - Maintain backward compatibility with existing method signatures - Centralize rate limiting and header management - Support extensible HTTP method handling * docs(drivers/mediafire): add comprehensive English comments - Add function-level comments for all major driver methods - Document Init, List, Link, MakeDir, Move, Rename, Copy, Remove, Put methods - Add comments for key utility functions including session token management - Improve code readability and maintainability for community collaboration - Follow Go documentation conventions with clear, concise descriptions * perf(mediafire): optimize memory allocation and type assertion performance - Pre-allocate slice capacity in getFiles and bitmap conversion to reduce reallocations - Cache file type check in uploadUnits to avoid repeated type assertions - Add uploadSingleUnitOptimized for os.File to eliminate redundant type checks - Optimize string to int conversion with proper error handling - Improve memory efficiency in file upload operations * fix(mediafire): upload without cache * feat(mediafire): add rate limiting to all API methods - Add WaitLimit(ctx) calls to all driver methods: List, Link, MakeDir, Move, Rename, Copy, Remove, Put - Ensure consistent rate limiting across all MediaFire API interactions - Follow project standard pattern used by other drivers * feat(mediafire): improve error handling consistency - Add context parameter to all HTTP API functions for proper context propagation - Update getForm, postForm and apiRequest to accept context parameter - Fix rate limiting to use caller context instead of background context - Ensure consistent error handling patterns across all API calls - Improve cancellation and timeout support * feat(mediafire): refactor resumableUpload to use io.ReadSeeker and improve upload handling * fix(mediafire): release section reader * feat: add disk usage * feat(drivers/mediafire): support concurrent upload (#1387) * feat(drivers): add MediaFire driver with concurrent upload support - Implement complete MediaFire storage driver with session token authentication - Support all core operations: List, Get, Link, Put, Copy, Move, Remove, Rename, MakeDir - Include thumbnail generation for media files - Handle MediaFire's resumable upload with intelligent and multi-unit transfers - Support concurrent chunk uploads using errgroup.NewOrderedGroupWithContext, using splitted file caching for large files - Optimize memory usage with adaptive buffer sizing (10MB-100MB (default)) - Include rate limiting and retry logic for API requests - Add proper error handling and progress reporting - Handle MediaFire's bitmap-based resumable upload protocol Closes PR #1322 * feat(stream): add DiscardSection method to StreamSectionReader for skipping data * feat(mediafire): refactor resumableUpload logic for improved upload handling and error management * fix(mediafire): stop cron job and clear action token in Drop method * . * fix(mediafire): optimize buffer sizing logic in uploadUnits method * fix(docs): remove duplicate MediaFire * fix(mediafire): revert 'optimization', large files should not be fully chached. --------- Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> Co-authored-by: Da3zKi7 <da3zki7@duck.com> Co-authored-by: D@' 3z K!7 <99719341+Da3zKi7@users.noreply.github.com> Co-authored-by: j2rong4cn <j2rong@qq.com> Co-authored-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> * fix(mediafire): optimize hash calculation in uploadUnits function * feat(drivers/mediafire): support concurrent upload (#1366) * feat(drivers): add MediaFire driver with concurrent upload support - Implement complete MediaFire storage driver with session token authentication - Support all core operations: List, Get, Link, Put, Copy, Move, Remove, Rename, MakeDir - Include thumbnail generation for media files - Handle MediaFire's resumable upload with intelligent and multi-unit transfers - Support concurrent chunk uploads using errgroup.NewOrderedGroupWithContext, using splitted file caching for large files - Optimize memory usage with adaptive buffer sizing (10MB-100MB (default)) - Include rate limiting and retry logic for API requests - Add proper error handling and progress reporting - Handle MediaFire's bitmap-based resumable upload protocol Closes PR #1322 * feat(stream): add DiscardSection method to StreamSectionReader for skipping data * feat(mediafire): refactor resumableUpload logic for improved upload handling and error management * fix(mediafire): stop cron job and clear action token in Drop method * . * fix(mediafire): optimize buffer sizing logic in uploadUnits method * fix(docs): remove duplicate MediaFire * fix(mediafire): revert 'optimization', large files should not be fully chached. --------- Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> Signed-off-by: D@' 3z K!7 <99719341+Da3zKi7@users.noreply.github.com> Co-authored-by: j2rong4cn <j2rong@qq.com> Co-authored-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> --------- Signed-off-by: ILoveScratch <ilovescratch@foxmail.com> Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> Signed-off-by: D@' 3z K!7 <99719341+Da3zKi7@users.noreply.github.com> Co-authored-by: D@' 3z K!7 <99719341+Da3zKi7@users.noreply.github.com> Co-authored-by: Da3zKi7 <da3zki7@duck.com> Co-authored-by: KirCute <951206789@qq.com> Co-authored-by: Suyunmeng <Susus0175@proton.me> Co-authored-by: j2rong4cn <j2rong@qq.com> Co-authored-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com>


Closes PR #1322
Description / 描述
MediaFire driver
Motivation and Context / 背景
Originally asked at AList repo by @ILoveScratch2
Relates to PR #1322
How Has This Been Tested? / 测试
Adding my account session values and uploading files of different sizes. Also this driver is currently released at AList repo.
Checklist / 检查清单
我已阅读 CONTRIBUTING 文档。
go fmtor prettier.我已使用
go fmt或 prettier 格式化提交的代码。我已为此 PR 添加了适当的标签(如无权限或需要的标签不存在,请在描述中说明,管理员将后续处理)。
我已在适当情况下使用"Request review"功能请求相关代码作者进行审查。
我已相应更新了相关仓库(若适用)。
NOTES:
Sorry for creating another PR, I have no permissions to push against original mediafire branch here.
Maybe a cron job is required to continuously new MediaFire token, in fact, token expires every 10 mins.
Thanks @ILoveScratch2 @suyunjing @j2rong4cn @KirCute for improvements of original AList implementation.