aboutsummaryrefslogtreecommitdiff

NineKt (I don’t really care about pronunciation, “nine-kay-tee” or “nine-Kate” or whatever you want) is a library written in Kotlin (and primarily targeting the JVM) that provides a client-side implementation to the 9P protocol. It targets any JVM application, especially those that run on Android.

The implementation of client-side 9P provided by NineKt and the expected server-side behavior are those described by the section 5 in 9front’s manual pages. All differences between this and the original Plan 9 from Bell Labs specification, or any other specification (provided by, e.g., forks of it), are therefore ignored.

Rationale

There are a bunch of reasons why NineKt was born:

  1. All other JVM implementations look dead.
  2. There is no Kotlin implementation yet.
  3. There seems to be no such thing for Android, but Android apps can create custom file systems in a bunch of ways. See the section named “A word on Android” below.
  4. I thought it would be fun to make.

Usage

The most important class, and also the fulcrum of the entire implementation, is NinePConnection. This class implements the 9P protocol on top of another unknown transport-layer protocol (although it’s usually TCP) provided, and managed, by a subclass of the NetworkPacketTransporter abstract class. For this reason, the NinePConnection’s constructor requires an instance of another class that implements NetworkPacketTransporter. It doesn’t need anything else.

The NetworkPacketTransporter class provides abstraction over the specific networking methods. This makes the classes using NetworkPacketTransporter independent of both the specific networking API and the underlying transport-layer protocol of choice, therefore allowing swapping the API or protocol at any time and vastly improves portability. With all this considered, since Java’s standard library provides a networking API already, I thought that an implementation based on that would be imperative, appreciated, and especially broadly used.

// This example uses one of the dial(2) formats for the address and port.
val npconn: NinePConnection
try {
    npconn = NinePConnection(NetworkPacketTransporterJavaNet("net!9p.mydomain.com!564"))
} catch (uhe: UnresolvableHostException) {
    // failed :(
    // what now?
}

While NetworkPacketTransporter’s implementation of choice initializes the transport-layer connection as soon as it’s instanced, this is not true for NinePConnection and the 9P connection it manages. The reason why this class behaves in such way lies in its purpose, which is to only expose methods that coincide 1:1 with 9P’s protocol message types. Therefore, providing an automated way to initialize the protocol would mix two levels of abstraction in the same class. For this purpose, the initNineP utility function is a shorthand that can do exactly this for you, although it’s possible to do so manually by using the 9P primitives.

A word on Android

Android 11 introduces (back) the support for FUSE (source), but this limits compatibility with certain versions of Android, and consequently certain devices.

Android has also been supporting the Storage Access Framework since version 4.4. [TODO]

Notes

  • Source files live in src/main/kotlin.
  • All manual page references (e.g. dial(2)) refer to 9front’s manual. The number between parentheses is the section number.
  • The horizontal margin for code comments and documentation is 120 characters. However, it can be surpassed if it’s really necessary

License

The Unlicense.