From 2dde9d75ed743837c5314555da5e212766d825f4 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 25 Aug 2023 20:12:49 +0100 Subject: [PATCH] Initial commit --- .envrc | 2 ++ Tuprules.tup | 2 ++ icalendar_actor.nimble | 5 +++ icalendar_components.prs | 10 ++++++ shell.nix | 5 +++ src/Tupfile | 4 +++ src/icalendar_actor.nim | 60 ++++++++++++++++++++++++++++++++++++ src/icalendar_components.nim | 26 ++++++++++++++++ 8 files changed, 114 insertions(+) create mode 100644 .envrc create mode 100644 Tuprules.tup create mode 100644 icalendar_actor.nimble create mode 100644 icalendar_components.prs create mode 100644 shell.nix create mode 100644 src/Tupfile create mode 100644 src/icalendar_actor.nim create mode 100644 src/icalendar_components.nim diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..d324c24 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +source_env .. +use nix diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..f902ead --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1,2 @@ +include ../syndicate-nim/depends.tup +NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src diff --git a/icalendar_actor.nimble b/icalendar_actor.nimble new file mode 100644 index 0000000..12ebe15 --- /dev/null +++ b/icalendar_actor.nimble @@ -0,0 +1,5 @@ +bin = @["icalendar_actor"] +license = "Unlicense" +requires: "nim", "syndicate" +srcDir = "src" +version = "20230825" diff --git a/icalendar_components.prs b/icalendar_components.prs new file mode 100644 index 0000000..7e6c7cc --- /dev/null +++ b/icalendar_components.prs @@ -0,0 +1,10 @@ +version 1. +embeddedType EntityRef.Cap . + +Component = [@label string @properties [Property ...] @components [Component ...]]. + +Property = [@label string @parameters Parameters @type string @values any ...]. + +Parameters = {symbol: string ...:...}. + +CalendarDataspace = . diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..745dd0e --- /dev/null +++ b/shell.nix @@ -0,0 +1,5 @@ +let + syndicate = builtins.getFlake "syndicate"; + pkgs = + import { overlays = (builtins.attrValues syndicate.overlays); }; +in pkgs.nim2Packages.syndicate_utils diff --git a/src/Tupfile b/src/Tupfile new file mode 100644 index 0000000..6c4abe9 --- /dev/null +++ b/src/Tupfile @@ -0,0 +1,4 @@ +include_rules +: foreach ../*.prs |> !preserves_schema_nim |> {schema} +: icalendar_actor.nim | $(SYNDICATE_PROTOCOL) {schema} |> !nim_bin |> {bin} +: {bin} |> !assert_built |> diff --git a/src/icalendar_actor.nim b/src/icalendar_actor.nim new file mode 100644 index 0000000..007e7b6 --- /dev/null +++ b/src/icalendar_actor.nim @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: ☭ Emery Hemingway +# SPDX-License-Identifier: Unlicense + +import std/[json, sequtils, tables, uri] +import preserves, preserves/jsonhooks, syndicate +from syndicate/protocols/dataspace import Observe + +import ./icalendar_components + +type Observe = dataspace.Observe[Cap] + +type BootArgs {.preservesDictionary.} = object + dataspace: Cap + +proc importCalendar(location: string): Component = + let uri = parseUri(location) + if uri.scheme != "file": + raiseAssert """only supported calendar schema is "file" ignoring """ & location + else: + var + js = parseFile(uri.path) + pr = jsonhooks.toPreserveHook(js, void) + if not result.fromPreserve(pr): + # TODO: convert directly from JsonNode + raise newException(ValueError, "Preserves was not a valid iCalendar component") + if result.label != "vcalendar": + raise newException(ValueError, "Preserves was not a valid vcalendar @component") + +proc toPreserveHook(prop: Property; E: typedesc): Preserve[E] = + initRecord(prop.label, + prop.parameters.toPreserve(E), + prop.`type`.toPreserve(E), + prop.values.toPreserve(E), + ) + +proc toPreserveHook(comp: Component; E: typedesc): Preserve[E] = + initRecord(comp.label, + comp.properties.toPreserve(E), + comp.components.toPreserve(E), + ) + +proc serve(turn: var Turn; url: string): Cap = + let ds = newDataspace(turn) + let calendar = importCalendar(url) + run(turn.facet) do (turn: var Turn): + for prop in calendar.properties: + discard publish(turn, ds, prop) + for comp in calendar.components: + discard publish(turn, ds, comp) + ds + +runActor("icalendar_actor") do (root: Cap; turn: var Turn): + connectStdio(root, turn) + stderr.writeLine "connected stdio to ", root + during(turn, root, ?BootArgs) do (ds: Cap): + stderr.writeLine "got dataspace at ", ds + during(turn, ds, ?Observe(pattern: !CalendarDataspace) ?? {0: grabLit()}) do (url: string): + let cap = serve(turn, url) + stderr.writeLine "serving ", url, " at ", cap + discard publish(turn, ds, initRecord("calendar", url.toPreserve(Cap), cap.toPreserve(Cap))) diff --git a/src/icalendar_components.nim b/src/icalendar_components.nim new file mode 100644 index 0000000..542c260 --- /dev/null +++ b/src/icalendar_components.nim @@ -0,0 +1,26 @@ + +import + preserves, std/tables + +type + CalendarDataspace* {.preservesRecord: "calendar".} = object + `url`*: string + `dataspace`* {.preservesEmbedded.}: Preserve[void] + + Property* {.preservesTuple.} = object + `label`*: string + `parameters`*: Parameters + `type`*: string + `values`* {.preservesTupleTail.}: seq[Preserve[void]] + + Parameters* = Table[Symbol, string] + Component* {.acyclic, preservesTuple.} = ref object + `label`*: string + `properties`*: seq[Property] + `components`*: seq[Component] + +proc `$`*(x: CalendarDataspace | Property | Parameters | Component): string = + `$`(toPreserve(x)) + +proc encode*(x: CalendarDataspace | Property | Parameters | Component): seq[byte] = + encode(toPreserve(x))