Kingfisher is a webserver platform for the Roc language.
It lets you build websites by defining your own Model. The model is held in memory. No need for SQL.Changes to the model are saved to disk in an event store.
The project is in an early stage. I am currently exploring the API. There will be many breaking changes. There will probably also be changes, how the data is stored on disk, without the possibility to migrate the data.
Please inform me, if you plan to use this platform, so I can keep your use case in mind and consider writing migrations.
Use the platform with the following roc-application-header:
app [init_model, update_model, handle_request!, Model] {
webserver: platform "https://github.com/ostcar/kingfisher/releases/download/v0.0.4/SHF-u_wznLGLRLdWiQ3XhuOwzrfXye9PhMGWmr36zzk.tar.br",
}
The platform requires a Model
. The Model
can be any valid roc type. For
example:
Model : {
modelVersion: U64,
users: List User,
admin: [NoAdmin, Admin Str],
books: List Str,
specialOption: Bool,
}
The platform needs three functions:
init_model: Model
update_model : Model, List (List U8) -> Result Model _
handle_request! : Http.Request, Model => Result Http.Response _
-
init_model:
init_model
has to return the first version of the model. Be careful, when changing this. Your events need to be compatible. -
update_model:
update_model
runs the events. Be careful, when changing the implementation. Old events can not be migrated. -
handle_request!:
handle_request!
is called for each HTTP requests. The function is called with theRequest
and theModel
and has to return aResult Response _
. -
save_event!: To change the model, you have to pattern match on the request method. Write requests (
POST
,PUT
,PATCH
andDELETE
) have an function as payload this function can be used to save an event.
when request.method is
Get ->
...
Post save_event! ->
save_event!(my_event)
An event is a List U8
. Make sure to implement update_model
to handle all of
your events.
The platform makes the distinction between a read and a write request on the
HTTP method. POST
, PUT
, PATCH
and DELETE
requests are write requests.
All other methods are read requests. This means, that a GET
request can not
alter the Model.
The platform can handle many read requests at the same time. But there can only be one concurrent write request. When a write request is processed, all other write request and all read requests have to wait.
All events are only persisted to disk, if handle_request!
returns with Ok. On
error, all events gets discarded.
All written events are stored in one file, that is called db.events
on
default. The name can be changed with the argument --events-file
. The file has
a binary format. It first contains the size of the first event, followed by the
first event. Then the size of the second event, followed by the second event and
so on.
The size of the event is written in the format provided by the go function binary.PutUvarint. For numbers up to 127, one byte is used. For numbers up to 16383, two bytes are used and so on.
The format of the events will probably change in the future.
To build the platform from source, you need to install
roc, go and
zig. Zig is used to
crosscompile the go code. At the moment, it only works with zig 0.11.0
.
Run:
roc build.roc
to build the platform for linux and mac.
Afterwards, the example can be run with:
roc run examples/hello_world/main.roc
-
At the moment, Roc does not have atomic refcounts. This means, that the parallel handling of read requests are not thread safe. Read requests can therefore crash the platform. I hope, atomic refcounts will land soon in Roc.
-
100 % CPU usage when running the platform with
roc run
. As a workaround, you can first build your platform withroc build
or useroc run
with--optimize
.
MIT