Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Let JsonSyncable use an app-supplied folder abstraction (Android SAF support)

オープン
#153 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 4 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
android, csharp

調査の方向性

Start by reading JsonSyncable and its existing DirectoryInfo constructor and file operations to identify the stream behaviors it needs. The issue proposes an ISyncFolder interface and a DirectoryInfo-backed implementation, while the Android SAF implementation is for FwLite. Done means JsonSyncable uses the abstraction for listing, reading, appending, and tail repair while existing callers and tests continue to work.

索引モデルが issue の本文から書いたものです。

説明

Goal

Let JsonSyncable sync through a folder the app supplies, so FwLite on Android can use a folder picked through the Storage Access Framework, such as a USB OTG flash drive. Today JsonSyncable takes a DirectoryInfo and uses System.IO directly. That doesn't work on Android: SAF gives document URIs, not file paths.

Why not an existing abstraction

  • System.IO.Abstractions (IFileSystem) copies the path-based System.IO API and has hundreds of members. Implemented over SAF, most of them would throw NotSupportedException, and Harmony could still call any of them.
  • Microsoft.Extensions.FileProviders (IFileProvider) is read-only.

Proposal

Add a narrow interface covering only what JsonSyncable does: list client files, read one, append to one, and repair a partial last line (read the end of the file, truncate).

public interface ISyncFolder
{
    IAsyncEnumerable<string> ListFilesAsync(CancellationToken ct);          // names only, e.g. "client_<guid>.jsonl"
    Task<Stream?> OpenReadAsync(string name, CancellationToken ct);         // null if missing; seekable
    Task<Stream> OpenAppendAsync(string name, CancellationToken ct);        // creates if missing
    Task<Stream?> OpenReadWriteAsync(string name, CancellationToken ct);    // seekable + SetLength, for tail repair
}
  • JsonSyncable keeps all the format logic: file naming, line parsing, and repairing a partial last line. The app only supplies streams.
  • Harmony ships a DirectoryInfo-backed implementation. The current constructor wraps it, so existing callers and tests don't change.
  • FwLite writes the Android implementation over ContentResolver.OpenFileDescriptor.

Android issues the design has to handle

  • Append: SAF's "wa" mode is ignored by some providers. Opening with "rw" and seeking to the end is safer.
  • Truncate: the tail repair cuts the file back to its last complete line. "rwt" only truncates to zero. Instead, open with "rw" and truncate the ParcelFileDescriptor's FileChannel. That needs a provider that returns a real file descriptor. ExternalStorageProvider, which serves mounted USB drives, does. Cloud-backed providers often return a pipe that can't seek. The fallback there is to copy the good part to a new file and replace the old one, and that choice belongs to the implementation.
  • Seeking: the tail check and the repair both seek. An implementation that can't seek should fail clearly rather than quietly skip the repair.
  • Listing cost: each DocumentFile call is an IPC round trip, so list names with one DocumentsContract query.
  • Locking: the static per-client AsyncLock only covers one process. On Android, opening a file doesn't lock it, so two apps syncing the same drive could interleave writes. Same as today, but more likely there.
主要言語
C#
スター
14
フォーク
4
平均マージ
5日 58分
マージ済み PR(30日)
15

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

sillsdev/harmony のほかの issue

sillsdev/harmony の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。