summaryrefslogtreecommitdiff
path: root/README.md
blob: e12376bfe34ad1a7b00ed4b78de250ec77749a11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
NineKt: Teaching Kotlin to speak 9P
===================================

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](https://en.wikipedia.org/wiki/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](https://man.9front.org/5/). 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](http://9p.cat-v.org/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.

```kotlin
// 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](https://source.android.com/docs/core/storage/scoped#fuse-performance-tuning)) the support
for [FUSE](https://en.wikipedia.org/wiki/Filesystem_in_Userspace) ([source](https://source.android.com/docs/core/storage/scoped#using-scoped-storage-with-fuse)),
but this limits compatibility with certain versions of Android, and consequently certain devices.

Android has also been supporting the [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider)
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](https://man.9front.org/). 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](https://unlicense.org/).