summaryrefslogtreecommitdiff
path: root/README.md
blob: 816398b750f24316fdc555771c53119782045058 (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
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 eases the process of implementing the [9P protocol](https://en.wikipedia.org/wiki/9P_(protocol))
into any JVM application, including those for Android.

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 only one you'll need for basic usage, 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 from both the specific networking API and the underlying transport-layer
protocol of choice. This allows 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 :(
}
```

While `NetworkPacketTransporter` implementation initializes the transport-layer connection as soon as it's instanced,
this is not true for `NinePConnection` and the 9P connection. The reason why the 9P protocol is not immediately
initialized is that `NinePConnection` only exposes methods that coincide with the protocol messages, which means that
providing an automated way to initialize the protocol would mix two levels of abstraction in the same class. For this
purpose, the `initNineP` function is a shorthand that can do it 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/).