Make FTP server a separate module#4602
Make FTP server a separate module#4602TranceLove wants to merge 11 commits intoTeamAmaze:release/4.0from
Conversation
- Replace EventBus with kotlinx.coroutines - FtpServerFragment update code to recommended
This enables future integration of other file services more easier.
There was a problem hiding this comment.
Pull request overview
This PR modularizes the FTP server feature by extracting it from the app module into a dedicated ftpserver library, coupled through a new server-core abstraction module to support future pluggable server implementations.
Changes:
- Added new Gradle modules:
server-core(server abstractions/registry) andftpserver(FTP implementation: engine, service/receiver base classes, filesystem adapters, UI, resources). - Updated
appintegration to use the new FTP module (newAppFtpService/AppFtpReceiver, updated fragment/tile/notification to referenceFtpPreferences/FtpServerEngine). - Added unit tests for FTP custom commands (AVBL/FEAT/PWD) and updated Kotlin stdlib version.
Reviewed changes
Copilot reviewed 62 out of 63 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle | Includes the new server-core and ftpserver modules. |
| server-core/** | Introduces server abstractions (types, preferences/notification interfaces, registry, events) and module Gradle config. |
| ftpserver/** | New FTP module: engine/service base, filesystem implementations, UI/resources, and unit tests. |
| app/** | Wires the app to the new FTP module (service/receiver, fragment, tile, notification) and adds a WebDAV certificate callable/test. |
| gradle/libs.versions.toml | Updates Kotlin stdlib version used by the project. |
| file_operations/src/test/** | Adds/updates a (currently empty/commented) test helper class. |
| app/play/release/output-metadata.json | Adds a generated build artifact (should likely not be committed). |
| plan-modularizeFtpServer.prompt.md | Planning documentation for the modularization work. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cbc759a to
ed9a33d
Compare
ed9a33d to
9f9a3f0
Compare
SshAuthenticationTaskTest.prepareSshConnectionPool() was storing a raw SSHClient Mockito mock directly into NetCopyClientConnectionPool.connections without wrapping it in SSHClientImpl. This caused a ClassCastException when shutdown() was called in AbstractSftpServerTest.tearDown(), since the lambda tried to cast the raw SSHClient (which is not a NetCopyClient) to NetCopyClient. The unhandled exception from the fire-and-forget runInBackground call was then rethrown as OnErrorNotImplementedException, leaving connections un-cleared. On the next test's setUp() call, the stale connection from SshAuthenticationTaskTest was still present in the pool. When validate() found it invalid and tried to reconnect via createSshClient(url), it required a DB lookup that found no matching entry (because the SshAuthenticationTaskTest connection used a different URL), causing FilesOnSshdTest.testListFilesWithSpecialChars to time out waiting for SFTP results. Fixes: - Wrap mock SSHClient in SSHClientImpl in prepareSshConnectionPool() so the connections map always holds proper NetCopyClient instances - Add tearDown() to SshAuthenticationTaskTest to reset sshClientFactory and clear the connections map after each test, preventing state leakage - Add sshClientFactory reset in AbstractSftpServerTest.setUp() as an additional safeguard against contamination from any preceding test class - Minor: refactor FilesOnSshdTest to use SAM lambda syntax for OnFileFound callbacks; extend atMost timeout to 120 seconds for testListFilesWithSpecialChars
9d063ea to
f49db29
Compare
1abd5de to
640126d
Compare
To complete the registry base approach
640126d to
502d11a
Compare
a60a1de to
94a6a98
Compare
|
Verified in Android 16 with daily FTP usage. |
EmmanuelMess
left a comment
There was a problem hiding this comment.
I still need to check some files and all the tests.
Also, I am not quite understanding the separation of concerns between app, ftpserver and server-core or if the server-core functionality is actually completely already in use.
| /** | ||
| * [TypeConverter] between [JSONObject] as object and String representation. | ||
| */ | ||
| object JsonTypeConverter { |
| /** | ||
| * Get the FTP service class to start/stop | ||
| */ | ||
| abstract fun getFtpServiceClass(): Class<*> |
There was a problem hiding this comment.
This should be out FtpServerService.
| context: Context, | ||
| intent: Intent, | ||
| ) { | ||
| logger.debug("Received: ${intent.action}") |
| */ | ||
| class AppFtpService : FtpServerService() { | ||
| private val serverNotification | ||
| get() = ServerRegistry.getProvider(ServerType.FTP)!!.getNotification() |
There was a problem hiding this comment.
Please don't use !! in new code.
| return getString(R.string.ftp_command_FEAT) | ||
| } | ||
|
|
||
| companion object { |
There was a problem hiding this comment.
Companion object should be on top.
| * | ||
| * Each server module should implement this to provide its components. | ||
| */ | ||
| interface ServerProvider { |
There was a problem hiding this comment.
This should probably be in another file.
| * | ||
| * Each server module should implement this to provide its components. | ||
| */ | ||
| interface ServerProvider { |
There was a problem hiding this comment.
Very similar to FileServer (see comment there).
| * Each server implementation should provide its own implementation of this interface | ||
| * to handle server lifecycle and configuration. | ||
| */ | ||
| interface FileServer { |
There was a problem hiding this comment.
Very similar to ServerProvider, not sure what "server lifecycle and configuration." means in this case.
There was a problem hiding this comment.
This should be in some llm specific folder somewhere. See https://github.com/EmmanuelMess/Multistep-DEVS-Simulator .claude and spec files folders for ideas.
There was a problem hiding this comment.
Also its current structure might not be useful, useful information would be:
- restrictions applied to the llm in code creation
- specfic set of specifications passed, initially and during refinement. Including UI/UX design files and diagrams
- a review of code of llm, and changed that were manually applied later
| │ ├── ServerPreferences.kt | ||
| │ └── ServerRegistry.kt | ||
|
|
||
| ftpserver/ |
There was a problem hiding this comment.
If possible this is better as a UML diagram of classes and such, not a semi formatted list. See https://github.com/EmmanuelMess/Multistep-DEVS-Simulator/blob/master/design/class%20diagrams/class%20diagram.svg for an example.
To prompt users to disable battery optimization for better network I/O performance when running FTP server. Fixes TeamAmaze#4603
94a6a98 to
b22a5e2
Compare
Description
Make FTP server a separate module, coupled via another server-core module, for facilitating integrations in the future.
Issue tracker
Automatic tests
Manual tests
Build tasks success
Successfully running following tasks on local:
./gradlew assembledebug./gradlew spotlessCheck