Use the (un)stable Nix C bindings

This commit is contained in:
Emery Hemingway 2023-12-08 08:24:29 +02:00
parent 5483b54158
commit 576157b901
15 changed files with 837 additions and 189 deletions

View File

@ -1,3 +1,2 @@
include_rules
: |> !nim_lk |> | ./<lock>
: lock.json |> !nim_cfg |> | ./<lock>

172
lock.json
View File

@ -1 +1,171 @@
{"depends":[{"method":"fetchzip","packages":["syndicate"],"path":"/nix/store/008s11kkqscfqxs6g29q77c38pnrlppi-source","ref":"20231005","rev":"552e51899c82c0c2f4f466382be7d8e22a1da689","sha256":"1j3k0zlh5z02adhfvb7rdqz8fjzc6gri4v3v1fgcv2h2b7vrf0dg","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/552e51899c82c0c2f4f466382be7d8e22a1da689.tar.gz"},{"method":"fetchzip","packages":["coap"],"path":"/nix/store/pqj933cnw7r7hp46jrpjlwh1yr0jvckp-source","ref":"20230331","rev":"a134213b51a8d250684f2ba26802ffa97fae4ffb","sha256":"1wbix6d8l26nj7m3xinh4m2f27n4ma0yzs3x5lpann2ha0y51k8b","srcDir":"src","url":"https://codeberg.org/eris/nim-coap/archive/a134213b51a8d250684f2ba26802ffa97fae4ffb.tar.gz"},{"method":"fetchzip","packages":["hashlib"],"path":"/nix/store/v03nzlpdgbfxd2zhcnkfbkq01d5kqxcl-source","rev":"84e0247555e4488594975900401baaf5bbbfb53","sha256":"1pfczsv8kl36qpv543f93d2y2vgz2acckssfap7l51s2x62m6qwx","srcDir":"","url":"https://github.com/khchen/hashlib/archive/84e0247555e4488594975900401baaf5bbbfb53.tar.gz"},{"method":"fetchzip","packages":["preserves"],"path":"/nix/store/vx6ihnickx7d5lwy69i8k7fsjicv33r3-source","ref":"20230914","rev":"c915accf7d2a36ca1f323e2f02e2df7375e815f1","sha256":"11rlcbs9mvk335ibkbj8fk9aslhmnlaiqhcsjpp5n04k447sr7nx","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/preserves-nim/archive/c915accf7d2a36ca1f323e2f02e2df7375e815f1.tar.gz"},{"method":"fetchzip","packages":["eris"],"path":"/nix/store/lxa6ba8r9hhs06k6f2iyznwjxix1klv1-source","ref":"20230823","rev":"49d8117367d3530533dc1d6a9111ddd134b08b1e","sha256":"0lq9a04cayf04nnhn0gvp5phlij0cis38v7cz7jmgks2xvz1bcbr","srcDir":"src","url":"https://codeberg.org/eris/nim-eris/archive/49d8117367d3530533dc1d6a9111ddd134b08b1e.tar.gz"},{"method":"fetchzip","packages":["cbor"],"path":"/nix/store/70cqa9s36dqnmsf179cn9psj77jhqi1l-source","ref":"20230619","rev":"a4a1affd45ba90bea24e08733ae2bd02fe058166","sha256":"005ib6im97x9pdbg6p0fy58zpdwdbkpmilxa8nhrrb1hnpjzz90p","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim_cbor/archive/a4a1affd45ba90bea24e08733ae2bd02fe058166.tar.gz"},{"method":"fetchzip","packages":["freedesktop_org"],"path":"/nix/store/98wncmx58cfnhv3y96lzwm22zvyk9b1h-source","ref":"20230210","rev":"fb04d0862aca4be2edcc0eafa94b1840030231c8","sha256":"0wj5m09x1pr36gv8p5r72p6l3wwl01y8scpnlzx7q0h5ij6jaj6s","srcDir":"src","url":"https://git.sr.ht/~ehmry/freedesktop_org/archive/fb04d0862aca4be2edcc0eafa94b1840030231c8.tar.gz"},{"method":"fetchzip","packages":["configparser"],"path":"/nix/store/4zl5v7i6cj3f9sayvsjcx2h20lqwr9a6-source","ref":"newSection","rev":"695f1285d63f1954c25eb1f42798d90fa7bcbe14","sha256":"0b0pb5i0kir130ia2zf8zcgdz8awms161i6p83ri3nbgibbjnr37","srcDir":"src","url":"https://github.com/ehmry/nim-configparser/archive/695f1285d63f1954c25eb1f42798d90fa7bcbe14.tar.gz"},{"method":"fetchzip","packages":["tkrzw"],"path":"/nix/store/4x9wxyli4dy719svg1zaww0c0b3xckp0-source","ref":"20220922","rev":"efd87edb7b063182c1a1fa018006a87b515d589b","sha256":"1h0sdvai4gkkz48xfh67wa1xz2k8bkkba8q6snnbllmhmywd9apb","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim-tkrzw/archive/efd87edb7b063182c1a1fa018006a87b515d589b.tar.gz"},{"method":"fetchzip","packages":["getdns"],"path":"/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source","ref":"20221222","rev":"c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6","sha256":"1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b","srcDir":"src","url":"https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"},{"method":"fetchzip","packages":["nimcrypto"],"path":"/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source","ref":"traditional-api","rev":"602c5d20c69c76137201b5d41f788f72afb95aa8","sha256":"1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65","srcDir":"","url":"https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"},{"method":"fetchzip","packages":["taps"],"path":"/nix/store/did1li0xk9qih80pvxqhjc4np3ijlfjj-source","ref":"20230331","rev":"4f9c9972d74eb39c662b43ed79d761e109bf00f1","sha256":"12qsizmisr1q0q4x37c5q6gmnqb5mp0bid7s3jlcsjvhc4jw2q57","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim_taps/archive/4f9c9972d74eb39c662b43ed79d761e109bf00f1.tar.gz"},{"method":"fetchzip","packages":["base32"],"path":"/nix/store/qcnchjsak3hyn4c6r0zd6qvm7j8y1747-source","ref":"0.1.3","rev":"f541038fbe49fdb118cc2002d29824b9fc4bfd61","sha256":"16gh1ifp9hslsg0is0v1ya7rxqfhq5hjqzc3pfdqvcgibp5ybh06","srcDir":"","url":"https://github.com/OpenSystemsLab/base32.nim/archive/f541038fbe49fdb118cc2002d29824b9fc4bfd61.tar.gz"},{"method":"fetchzip","packages":["npeg"],"path":"/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source","ref":"1.2.1","rev":"26d62fdc40feb84c6533956dc11d5ee9ea9b6c09","sha256":"0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh","srcDir":"src","url":"https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"}]}
{
"depends": [
{
"method": "fetchzip",
"packages": [
"base32"
],
"path": "/nix/store/qcnchjsak3hyn4c6r0zd6qvm7j8y1747-source",
"ref": "0.1.3",
"rev": "f541038fbe49fdb118cc2002d29824b9fc4bfd61",
"sha256": "16gh1ifp9hslsg0is0v1ya7rxqfhq5hjqzc3pfdqvcgibp5ybh06",
"srcDir": "",
"url": "https://github.com/OpenSystemsLab/base32.nim/archive/f541038fbe49fdb118cc2002d29824b9fc4bfd61.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"cbor"
],
"path": "/nix/store/70cqa9s36dqnmsf179cn9psj77jhqi1l-source",
"ref": "20230619",
"rev": "a4a1affd45ba90bea24e08733ae2bd02fe058166",
"sha256": "005ib6im97x9pdbg6p0fy58zpdwdbkpmilxa8nhrrb1hnpjzz90p",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim_cbor/archive/a4a1affd45ba90bea24e08733ae2bd02fe058166.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"coap"
],
"path": "/nix/store/pqj933cnw7r7hp46jrpjlwh1yr0jvckp-source",
"ref": "20230331",
"rev": "a134213b51a8d250684f2ba26802ffa97fae4ffb",
"sha256": "1wbix6d8l26nj7m3xinh4m2f27n4ma0yzs3x5lpann2ha0y51k8b",
"srcDir": "src",
"url": "https://codeberg.org/eris/nim-coap/archive/a134213b51a8d250684f2ba26802ffa97fae4ffb.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"configparser"
],
"path": "/nix/store/4zl5v7i6cj3f9sayvsjcx2h20lqwr9a6-source",
"ref": "newSection",
"rev": "695f1285d63f1954c25eb1f42798d90fa7bcbe14",
"sha256": "0b0pb5i0kir130ia2zf8zcgdz8awms161i6p83ri3nbgibbjnr37",
"srcDir": "src",
"url": "https://github.com/ehmry/nim-configparser/archive/695f1285d63f1954c25eb1f42798d90fa7bcbe14.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"eris"
],
"path": "/nix/store/lxa6ba8r9hhs06k6f2iyznwjxix1klv1-source",
"ref": "20230823",
"rev": "49d8117367d3530533dc1d6a9111ddd134b08b1e",
"sha256": "0lq9a04cayf04nnhn0gvp5phlij0cis38v7cz7jmgks2xvz1bcbr",
"srcDir": "src",
"url": "https://codeberg.org/eris/nim-eris/archive/49d8117367d3530533dc1d6a9111ddd134b08b1e.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"freedesktop_org"
],
"path": "/nix/store/98wncmx58cfnhv3y96lzwm22zvyk9b1h-source",
"ref": "20230210",
"rev": "fb04d0862aca4be2edcc0eafa94b1840030231c8",
"sha256": "0wj5m09x1pr36gv8p5r72p6l3wwl01y8scpnlzx7q0h5ij6jaj6s",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/freedesktop_org/archive/fb04d0862aca4be2edcc0eafa94b1840030231c8.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"getdns"
],
"path": "/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source",
"ref": "20221222",
"rev": "c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6",
"sha256": "1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"hashlib"
],
"path": "/nix/store/fav82xdbicvlk34nmcbl89zx99lr3mbs-source",
"rev": "f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac",
"sha256": "1sx6j952lj98629qfgr7ds5aipyw9d6lldcnnqs205wpj4pkcjb3",
"srcDir": "",
"url": "https://github.com/ehmry/hashlib/archive/f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"nimcrypto"
],
"path": "/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source",
"ref": "traditional-api",
"rev": "602c5d20c69c76137201b5d41f788f72afb95aa8",
"sha256": "1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65",
"srcDir": "",
"url": "https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"npeg"
],
"path": "/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source",
"ref": "1.2.1",
"rev": "26d62fdc40feb84c6533956dc11d5ee9ea9b6c09",
"sha256": "0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh",
"srcDir": "src",
"url": "https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"preserves"
],
"path": "/nix/store/fmb2yckksz7iv3qdkk5gk1j060kppkq9-source",
"ref": "20231102",
"rev": "4faeb766dc3945bcfacaa1a836ef6ab29b20ceb0",
"sha256": "1a3g5bk1l1h250q3p6sqv6r1lpsplp330qqyp48r0i4a5r0jksq3",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/4faeb766dc3945bcfacaa1a836ef6ab29b20ceb0.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"syndicate"
],
"path": "/nix/store/nhpvl223vbzdrlzikw7pgyfxs344w7ma-source",
"ref": "20231108",
"rev": "095418032180e360ea27ec7fcd63193944b68e2c",
"sha256": "09pbml2chzz0v5zpz67fs7raj0mfmg8qrih2vz85xxc51h7ncqvw",
"srcDir": "src",
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/095418032180e360ea27ec7fcd63193944b68e2c.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"taps"
],
"path": "/nix/store/did1li0xk9qih80pvxqhjc4np3ijlfjj-source",
"ref": "20230331",
"rev": "4f9c9972d74eb39c662b43ed79d761e109bf00f1",
"sha256": "12qsizmisr1q0q4x37c5q6gmnqb5mp0bid7s3jlcsjvhc4jw2q57",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/4f9c9972d74eb39c662b43ed79d761e109bf00f1.tar.gz"
},
{
"method": "fetchzip",
"packages": [
"tkrzw"
],
"path": "/nix/store/4x9wxyli4dy719svg1zaww0c0b3xckp0-source",
"ref": "20220922",
"rev": "efd87edb7b063182c1a1fa018006a87b515d589b",
"sha256": "1h0sdvai4gkkz48xfh67wa1xz2k8bkkba8q6snnbllmhmywd9apb",
"srcDir": "src",
"url": "https://git.sr.ht/~ehmry/nim-tkrzw/archive/efd87edb7b063182c1a1fa018006a87b515d589b.tar.gz"
}
]
}

View File

@ -1,4 +1,4 @@
version = "20231009"
version = "20231208"
author = "Emery Hemingway"
description = "Syndicated Nix Actor"
license = "Unlicense"

View File

@ -10,7 +10,7 @@ Realise = <realise @drv string @outputs StringSeq> .
Instantiate = <instantiate @expr string @options AttrSet @result any> .
Eval = <eval @expr string @options {symbol: any ...:...} @result any> .
Eval = <eval @expr string @path string @result any> .
Narinfo = <narinfo @path string @info AttrSet> .

View File

@ -3,14 +3,15 @@
let
nix' = pkgs.nix.overrideAttrs (final: prev: {
src = pkgs.fetchFromGitHub {
owner = "NixOS";
owner = "tweag";
repo = "nix";
rev = "2.13.3";
hash = "sha256-jUc2ccTR8f6MGY2pUKgujm+lxSPNGm/ZAP+toX+nMNc=";
rev = "nix-c-bindings";
hash = "sha256-xOyU79lsz0THOj1LccfsDS45089n2DhlkWxaJFeKriY=";
};
});
in pkgs.nim2Packages.buildNimPackage {
in pkgs.buildNimPackage {
name = "dummy";
nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = [ pkgs.boost nix' ];
lockFile = ./lock.json;
}

View File

@ -1,184 +1,81 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[json, os, osproc, strutils, tables]
import eris/memory_stores
import preserves, preserves/jsonhooks
import syndicate, syndicate/relays
from syndicate/protocols/dataspace import Observe
import ./nix_actor/[clients, daemons]
import ./nix_actor/libnix/[libexpr, main, stdpuspus, store]
import std/[os, strutils, tables]
import preserves, syndicate, syndicate/relays
# from syndicate/protocols/dataspace import Observe
import ./nix_actor/[nix_api, nix_api_value]
import ./nix_actor/protocol
var nixVersion {.importcpp: "nix::nixVersion", header: "globals.hh".}: StdString
type
Value = Preserve[void]
Observe = dataspace.Observe[Cap]
proc toPreserve(state: EvalState; val: libexpr.ValueObj | libExpr.ValuePtr; E = void): Preserve[E] {.gcsafe.} =
## Convert a Nix value to a Preserves value.
# See nix::printValueAsJSON
case val.kind
of nInt:
result = val.integer.toPreserve(E)
of nFloat:
result = val.fpoint.toPreserve(E)
of nBool:
result = val.boolean.toPreserve(E)
of nString:
result = val.shallowString.toPreserve(E)
of nPath:
result = toSymbol($val.path, E)
of nNull:
proc toPreserve(state: State; value: Value; E = void): Preserve[E] {.gcsafe.} =
var ctx: NixContext
stderr.writeLine get_type(ctx, value).int
case get_type(ctx, value)
of NIX_TYPE_THUNK: raiseAssert "cannot preserve thunk"
of NIX_TYPE_INT:
result = getInt(ctx, value).toPreserve(E)
of NIX_TYPE_FLOAT:
result = getFloat(ctx, value).toPreserve(E)
of NIX_TYPE_BOOL:
result = getBool(ctx, value).toPreserve(E)
of NIX_TYPE_STRING:
result = ($getString(ctx, value)).toPreserve(E)
of NIX_TYPE_PATH:
result = ($getPathString(ctx, value)).toPreserve(E)
of NIX_TYPE_NULL:
result = initRecord[E]("null")
of nAttrs:
of NIX_TYPE_ATTRS:
result = initDictionary(E)
for sym, attr in val.pairs:
let key = symbolString(state, sym).toSymbol(E)
# Nix string to Nim string to Preserves symbol
result[key] = state.toPreserve(attr, E)
of nList:
result = initSequence(0, E)
for e in val.items:
result.sequence.add(state.toPreserve(e, E))
else:
raise newException(ValueError, "cannot preserve " & $val.kind)
proc eval(state: EvalState; code: string): Value =
## Evaluate Nix `code` to a Preserves value.
var nixVal: libexpr.ValueObj
let expr = state.parseExprFromString(code, getCurrentDir())
state.eval(expr, nixVal)
state.forceValueDeep(nixVal)
state.toPreserve(nixVal, void)
proc parseArgs(args: var seq[string]; opts: AttrSet) =
for sym, val in opts:
add(args, "--" & $sym)
if not val.isString "":
var js: JsonNode
if fromPreserve(js, val): add(args, $js)
else: stderr.writeLine "invalid option --", sym, " ", val
#[
proc parseNarinfo(info: var AttrSet; text: string) =
var
key, val: string
off: int
while off < len(text):
off = off + parseUntil(text, key, ':', off) + 1
off = off + skipWhitespace(text, off)
off = off + parseUntil(text, val, '\n', off) + 1
if key != "" and val != "":
if allCharsInSet(val, Digits):
info[Symbol key] = val.parsePreserves
else:
info[Symbol key] = val.toPreserve
proc narinfo(turn: var Turn; ds: Cap; path: string) =
let
client = newAsyncHttpClient()
url = "https://cache.nixos.org/" & path & ".narinfo"
futGet = get(client, url)
addCallback(futGet, turn) do (turn: var Turn):
let resp = read(futGet)
if code(resp) != Http200:
close(client)
else:
let futBody = body(resp)
addCallback(futBody, turn) do (turn: var Turn):
close(client)
var narinfo = Narinfo(path: path)
parseNarinfo(narinfo.info, read(futBody))
discard publish(turn, ds, narinfo)
]# # I never link to openssl if I can avoid it.
proc build(spec: string): Build =
var execOutput = execProcess("nix", args = ["build", "--json", "--no-link", spec], options = {poUsePath})
var js = parseJson(execOutput)
Build(input: spec, output: js[0].toPreserve)
proc realise(realise: Realise): seq[string] =
var execlines = execProcess("nix-store", args = ["--realize", realise.drv], options = {poUsePath})
split(strip(execlines), '\n')
proc instantiate(instantiate: Instantiate): Value =
const cmd = "nix-instantiate"
var args = @["--expr", instantiate.expr]
parseArgs(args, instantiate.options)
var execOutput = strip execProcess(cmd, args = args, options = {poUsePath})
execOutput.toPreserve
proc bootNixFacet(turn: var Turn; ds: Cap): Facet =
# let store = openStore()
result = inFacet(turn) do (turn: var Turn):
during(turn, ds, ?Observe(pattern: !Build) ?? {0: grabLit()}) do (spec: string):
discard publish(turn, ds, build(spec))
during(turn, ds, ?Observe(pattern: !Realise) ?? {0: grabLit()}) do (drvPath: string):
var ass = Realise(drv: drvPath)
ass.outputs = realise(ass)
discard publish(turn, ds, ass)
during(turn, ds, ?Observe(pattern: !Instantiate) ?? {0: grabLit(), 1: grabDict()}) do (e: string, o: Value):
var ass = Instantiate(expr: e)
if not fromPreserve(ass.options, unpackLiterals(o)):
stderr.writeLine "invalid options ", o
else:
ass.result = instantiate(ass)
discard publish(turn, ds, ass)
#[
during(turn, ds, ?Observe(pattern: !Narinfo) ?? {0: grabLit()}) do (path: string):
narinfo(turn, ds, path)
]#
let n = getAttrsSize(ctx, value)
var i: cuint
while i < n:
var (key, val) = get_attr_byidx(ctx, value, state, i)
inc(i)
result[toSymbol($key, E)] = toPreserve(state, val, E)
stderr.writeLine(result)
# close(val)
of NIX_TYPE_LIST:
let n = getListSize(ctx, value)
result = initSequence(n, E)
var i: cuint
while i < n:
var val = getListByIdx(ctx, value, state, i)
result[i] = toPreserve(state, val, E)
inc(i)
# close(val)
of NIX_TYPE_FUNCTION, NIX_TYPE_EXTERNAL:
raiseAssert "TODO: need a failure type"
type
CapArgs {.preservesDictionary.} = object
BootArgs {.preservesDictionary.} = object
dataspace: Cap
ClientSideArgs {.preservesDictionary.} = object
`listen-socket`: string
DaemonSideArgs {.preservesDictionary.} = object
`daemon-socket`: string
proc runNixActor(nixState: EvalState) =
let erisStore = newMemoryStore()
proc main() =
initLibexpr()
runActor("nix_actor") do (root: Cap; turn: var Turn):
connectStdio(root, turn)
connectStdio(turn, root)
let pat = ?CapArgs
during(turn, root, pat) do (ds: Cap):
during(turn, root, ?BootArgs) do (ds: Cap):
let
store = openStore()
state = newState(store)
discard publish(turn, ds,
initRecord("nixVersion", toPreserve($nixVersion.c_str)))
discard bootNixFacet(turn, ds)
let pat = ?Observe(pattern: !Eval) ?? {0: grabLit(), 1: grabDict()}
during(turn, ds, pat) do (e: string, o: Assertion):
var ass = Eval(expr: e)
doAssert fromPreserve(ass.options, unpackLiterals(o))
# unused options
let pat = ?Observe(pattern: !Eval) ?? {0: grabLit(), 1: grabLit()}
during(turn, ds, pat) do (expr: string, path: string):
var
value: Value
ass = Eval(expr: expr, path: path)
try:
ass.result = eval(nixState, ass.expr)
value = evalFromString(state, ass.expr, ass.path)
force(state, value)
ass.result = toPreserve(state, value, void)
discard publish(turn, ds, ass)
except CatchableError as err:
stderr.writeLine "failed to evaluate ", ass.expr, ": ", err.msg
except StdException as err:
stderr.writeLine "failed to evaluate ", ass.expr, ": ", err.what
during(turn, root, ?ClientSideArgs) do (socketPath: string):
bootClientSide(turn, ds, erisStore, socketPath)
during(turn, root, ?DaemonSideArgs) do (socketPath: string):
bootDaemonSide(turn, ds, erisStore, socketPath)
proc main =
initNix()
initGC()
let nixStore = openStore()
runNixActor(newEvalState(nixStore))
close(value)
do:
close(state)
close(store)
main()

View File

@ -1 +0,0 @@
backend:cpp

View File

@ -155,14 +155,11 @@ proc callDaemon(turn: var Turn; path: string; action: proc (daemon: Session; tur
proc bootDaemonSide*(turn: var Turn; ds: Cap; store: ErisStore; socketPath: string) =
during(turn, ds, ?Observe(pattern: !Missing) ?? {0: grab()}) do (a: Preserve[Cap]):
during(turn, ds, ?Observe(pattern: !Missing) ?? {0: grab()}) do (targets: Literal[StringSeq]):
# cannot use `grabLit` here because an array is a compound
# TODO: unpack to a `Pattern`
let daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
var targets: StringSeq
doAssert targets.fromPreserve(unpackLiterals(a))
# unpack <arr [<lit " …">]>
let missFut = queryMissing(daemon, targets)
let missFut = queryMissing(daemon, targets.value)
addCallback(missFut, turn) do (turn: var Turn):
close(daemon)
var miss = read(missFut)
@ -180,15 +177,12 @@ proc bootDaemonSide*(turn: var Turn; ds: Cap; store: ErisStore; socketPath: stri
do:
close(daemon)
during(turn, ds, ?Observe(pattern: !PathInfo) ?? {1: grabDict()}) do (pat: Value):
var daemon: Session
var request: AddToStoreClientAttrs
if request.fromPreserve(unpackLiterals pat):
daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
let fut = addToStore(daemon, store, request)
addCallback(fut, turn) do (turn: var Turn):
close(daemon)
var (path, info) = read(fut)
discard publish(turn, ds, initRecord("path", path.toPreserve, info.toPreserve))
during(turn, ds, ?Observe(pattern: !PathInfo) ?? {1: grabDict()}) do (request: Literal[AddToStoreClientAttrs]):
let daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
let fut = addToStore(daemon, store, request.value)
addCallback(fut, turn) do (turn: var Turn):
close(daemon)
var (path, info) = read(fut)
discard publish(turn, ds, initRecord("path", path.toPreserve, info.toPreserve))
do:
close(daemon)

58
src/nix_actor/nix_api.nim Normal file
View File

@ -0,0 +1,58 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import ./nix_api_types, ./nix_api_util, ./nix_api_value, ./nix_api_store, ./nix_api_expr
export NixContext, Store, State, Value, ValueType,
gc_decref, isNil
{.passC: staticExec("pkg-config --cflags nix-expr-c").}
{.passL: staticExec("pkg-config --libs nix-expr-c").}
# Always pass NixContext as a nil pointer.
proc initLibexpr* =
var ctx: NixContext
discard libexpr_init(ctx)
proc openStore*(uri: string, params: varargs[string]): Store =
var ctx: NixContext
var args = allocCStringArray(params)
defer: deallocCStringArray(args)
result = store_open(ctx, uri, addr args)
proc openStore*(): Store =
var ctx: NixContext
result = store_open(ctx, nil, nil)
proc close*(store: Store) = store_unref(store)
proc newState*(store: Store; searchPath: varargs[string]): State =
var ctx: NixContext
var path = allocCStringArray(searchPath)
defer: deallocCStringArray(path)
result = state_create(ctx, path, store)
proc close*(state: State) = state_free(state)
proc newValue*(state: State): Value =
var ctx: NixContext
alloc_value(ctx, state)
proc evalFromString*(state: State; expr, path: string): Value =
var ctx: NixContext
result = alloc_value(ctx, state)
discard expr_eval_from_string(ctx, state, expr, path, result)
proc close*(value: Value) =
var ctx: NixContext
discard gc_decref(ctx, cast[pointer](value))
proc force*(state: State; value: Value) =
var ctx: NixContext
discard value_force(ctx, state, value)
proc get_attr_byidx*(ctx: NixContext; value: Value; state: State; i: cuint): (cstring, Value) =
var ctx: NixContext
result[1] = get_attr_byidx(ctx, value, state, i, addr result[0])

View File

@ -0,0 +1,28 @@
## Module generated by c2nim for nix_api_expr.h
import ./nix_api_types
{.pragma: nix_api_expr, header: "nix_api_expr.h", importc: "nix_$1".}
proc libexpr_init*(context: NixContext): nix_err {.nix_api_expr.}
proc expr_eval_from_string*(context: NixContext; state: State; expr: cstring; path: cstring; value: Value): nix_err {.nix_api_expr.}
proc value_call*(context: NixContext; state: State; fn: Value; arg: Value; value: Value): nix_err {.nix_api_expr.}
proc value_force*(context: NixContext; state: State; value: Value): nix_err {.nix_api_expr.}
proc value_force_deep*(context: NixContext; state: State; value: Value): nix_err {.nix_api_expr.}
proc state_create*(context: NixContext; searchPath: cstringArray; store: Store): State {.nix_api_expr.}
proc state_free*(state: State) {.nix_api_expr.}
proc gc_incref*(context: NixContext; `object`: pointer): nix_err {.nix_api_expr.}
proc gc_decref*(context: NixContext; `object`: pointer): nix_err {.nix_api_expr.}
proc gc_now*() {.nix_api_expr.}
proc gc_register_finalizer*(obj: pointer; cd: pointer; finalizer: proc (obj: pointer; cd: pointer)) {.nix_api_expr.}

View File

@ -0,0 +1,26 @@
## Module generated by c2nim for nix_api_store.h
import ./nix_api_types
{.pragma: nix_api_store, header: "nix_api_store.h", importc: "nix_$1".}
proc libstore_init*(context: NixContext): nix_err {.nix_api_store.}
proc init_plugins*(context: NixContext): nix_err {.nix_api_store.}
proc store_open*(a1: NixContext; uri: cstring; params: ptr cstringArray): Store {.nix_api_store.}
proc store_unref*(store: Store) {.nix_api_store.}
proc store_get_uri*(context: NixContext; store: Store; dest: cstring; n: cuint): nix_err {.nix_api_store.}
proc store_parse_path*(context: NixContext; store: Store; path: cstring): StorePath {.nix_api_store.}
proc store_path_free*(p: StorePath) {.nix_api_store.}
proc store_is_valid_path*(context: NixContext; store: Store; path: StorePath): bool {.nix_api_store.}
proc store_build*(context: NixContext; store: Store; path: StorePath; userdata: pointer; callback: proc (userdata: pointer; outname: cstring; `out`: cstring)): nix_err {.nix_api_store.}
proc store_get_version*(a1: NixContext; store: Store; dest: cstring; n: cuint): nix_err {.nix_api_store.}

View File

@ -0,0 +1,35 @@
## Module generated by c2nim for nix_api_util.h
import ./nix_api_types
{.pragma: nix_api_util, header: "nix_api_util.h", importc: "nix_$1".}
{.pragma: importUtil, header: "nix_api_util.h", importc.}
var
NIX_OK* {.importUtil.}: cint
NIX_ERR_UNKNOWN* {.importUtil.}: cint
NIX_ERR_OVERFLOW* {.importUtil.}: cint
NIX_ERR_KEY* {.importUtil.}: cint
NIX_ERR_NIX_ERROR* {.importUtil.}: cint
proc c_context_create*(): NixContext {.nix_api_util.}
proc c_context_free*(context: NixContext) {.nix_api_util.}
proc libutil_init*(context: NixContext): nix_err {.nix_api_util.}
proc setting_get*(context: NixContext; key: cstring; value: cstring; n: cint): nix_err {.nix_api_util.}
proc setting_set*(context: NixContext; key: cstring; value: cstring): nix_err {.nix_api_util.}
proc version_get*(): cstring {.nix_api_util.}
proc err_msg*(context: NixContext; ctx: NixContext; n: ptr cuint): cstring {.nix_api_util.}
proc err_info_msg*(context: NixContext; read_context: NixContext; value: cstring; n: cint): nix_err {.nix_api_util.}
proc err_name*(context: NixContext; read_context: NixContext; value: cstring; n: cint): nix_err {.nix_api_util.}
proc err_code*(read_context: NixContext): nix_err {.nix_api_util.}
proc set_err_msg*(context: NixContext; err: nix_err; msg: cstring): nix_err {.nix_api_util.}

View File

@ -0,0 +1,72 @@
## Module generated by c2nim for nix_api_value.h
import ./nix_api_types
type
PrimOpFun* = proc (user_data: pointer; context: NixContext; state: ptr State; args: ptr Value; ret: Value)
# proc alloc_primop*(context: NixContext; fun: PrimOpFun; arity: cint; name: cstring; args: cstringArray; doc: cstring; user_data: pointer): ptr PrimOp {.importc: "nix_$1", header: "nix_api_value.h".}
# proc register_primop*(context: NixContext; primOp: ptr PrimOp): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc alloc_value*(context: NixContext; state: State): Value {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_type*(context: NixContext; value: Value): ValueType {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_typename*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_bool*(context: NixContext; value: Value): bool {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_string*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_path_string*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_list_size*(context: NixContext; value: Value): cuint {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_attrs_size*(context: NixContext; value: Value): cuint {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_float*(context: NixContext; value: Value): cdouble {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_int*(context: NixContext; value: Value): int64 {.importc: "nix_$1", header: "nix_api_value.h".}
# proc get_external*(context: NixContext; a2: Value): ptr ExternalValue {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_list_byidx*(context: NixContext; value: Value; state: State; ix: cuint): Value {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_attr_byname*(context: NixContext; value: Value; state: State; name: cstring): Value {.importc: "nix_$1", header: "nix_api_value.h".}
proc has_attr_byname*(context: NixContext; value: Value; state: State; name: cstring): bool {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_attr_byidx*(context: NixContext; value: Value; state: State; i: cuint; name: ptr cstring): Value {.importc: "nix_$1", header: "nix_api_value.h".}
proc get_attr_name_byidx*(context: NixContext; value: Value; state: State; i: cuint): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_bool*(context: NixContext; value: Value; b: bool): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_string*(context: NixContext; value: Value; str: cstring): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_path_string*(context: NixContext; value: Value; str: cstring): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_float*(context: NixContext; value: Value; d: cdouble): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_int*(context: NixContext; value: Value; i: int64): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_null*(context: NixContext; value: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
# proc set_external*(context: NixContext; value: Value; val: ptr ExternalValue): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc make_list*(context: NixContext; s: State; value: Value; size: cuint): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc set_list_byidx*(context: NixContext; value: Value; ix: cuint; elem: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
# proc make_attrs*(context: NixContext; value: Value; b: ptr BindingsBuilder): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
# proc set_primop*(context: NixContext; value: Value; op: ptr PrimOp): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
proc copy_value*(context: NixContext; value: Value; source: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
# proc make_bindings_builder*(context: NixContext; state: State; capacity: csize_t): ptr BindingsBuilder {.importc: "nix_$1", header: "nix_api_value.h".}
# proc bindings_builder_insert*(context: NixContext; builder: ptr BindingsBuilder; name: cstring; value: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
# proc bindings_builder_free*(builder: ptr BindingsBuilder) {.importc: "nix_$1", header: "nix_api_value.h".}

369
src/nix_actor/old.nim Normal file
View File

@ -0,0 +1,369 @@
type
Snoop = ref object
client, daemon: AsyncSocket
buffer: seq[Word]
version: Version
type ValidPathInfo = object
path: string
deriver: string
narHash: string
references: StringSet
registrationTime, narSize: BiggestInt
ultimate: bool
sigs: StringSet
ca: string
proc send(session: Snoop; sock: AsyncSocket; words: varargs[Word]): Future[void] =
for i, word in words: session.buffer[i] = word
send(sock, addr session.buffer[0], words.len shl 3)
proc send(session: Snoop; sock: AsyncSocket; s: string): Future[void] =
let wordCount = (s.len + 7) shr 3
if wordCount > session.buffer.len: setLen(session.buffer, wordCount)
session.buffer[0] = Word s.len
if wordCount > 0:
session.buffer[wordCount] = 0x00
copyMem(addr session.buffer[1], unsafeAddr s[0], s.len)
send(sock, addr session.buffer[0], (succ wordCount) shl 3)
proc passWord(a, b: AsyncSocket): Future[Word] {.async.} =
var w = await recvWord(a)
await send(b, addr w, sizeof(Word))
return w
proc passString(session: Snoop; a, b: AsyncSocket): Future[string] {.async.} =
var s = await recvString(a)
await send(session, b, s)
return s
proc passStringSeq(session: Snoop; a, b: AsyncSocket): Future[seq[string]] {.async.} =
let count = int(await passWord(a, b))
var strings = newSeq[string](count)
for i in 0..<count: strings[i] = await passString(session, a, b)
return strings
proc passStringSet(session: Snoop; a, b: AsyncSocket): Future[StringSet] {.async.} =
let count = int(await passWord(a, b))
var strings = initHashSet[string](count)
for i in 0..<count: incl(strings, await passString(session, a, b))
return strings
proc passStringMap(session: Snoop; a, b: AsyncSocket): Future[StringTableCap] {.async.} =
var table = newStringTable(modeCaseSensitive)
let n = await passWord(a, b)
for i in 1..n:
var
key = await passString(session, a, b)
val = await passString(session, a, b)
table[key] = val
return table
proc passClientWord(session: Snoop): Future[Word] =
passWord(session.client, session.daemon)
proc passDaemonWord(session: Snoop): Future[Word] =
passWord(session.daemon, session.client)
proc passClientString(session: Snoop): Future[string] =
passString(session, session.client, session.daemon)
proc passDaemonString(session: Snoop): Future[string] =
passString(session, session.daemon, session.client)
proc passClientStringSeq(session: Snoop): Future[seq[string]] =
passStringSeq(session, session.client, session.daemon)
proc passDaemonStringSeq(session: Snoop): Future[seq[string]] =
passStringSeq(session, session.daemon, session.client)
proc passClientStringSet(session: Snoop): Future[StringSet] =
passStringSet(session, session.client, session.daemon)
proc passDaemonStringSet(session: Snoop): Future[StringSet] =
passStringSet(session, session.daemon, session.client)
proc passClientStringMap(session: Snoop): Future[StringTableCap] =
passStringMap(session, session.client, session.daemon)
proc passDaemonStringMap(session: Snoop): Future[StringTableCap] =
passStringMap(session, session.daemon, session.client)
proc passDaemonValidPathInfo(session: Snoop; includePath: bool): Future[PathInfo] {.async.} =
var info: PathInfo
if includePath:
info.path = await passDaemonString(session)
info.deriver = await passDaemonString(session)
info.narHash = await passDaemonString(session)
info.references = await passDaemonStringSet(session)
info.registrationTime = BiggestInt(await passDaemonWord(session))
info.narSize = BiggestInt(await passDaemonWord(session))
assert session.version.minor >= 16
info.ultimate = (await passDaemonWord(session)) != 0
info.sigs = await passDaemonStringSet(session)
info.ca = await passDaemonString(session)
return info
proc passChunks(session: Snoop; a, b: AsyncSocket): Future[int] {.async.} =
var total: int
while true:
let chunkLen = int(await passWord(a, b))
if chunkLen == 0:
break
else:
let wordLen = (chunkLen + 7) shr 3
if session.buffer.len < wordLen: setLen(session.buffer, wordLen)
let recvLen = await recvInto(a, addr session.buffer[0], chunkLen)
# each chunk must be recved contiguously
if recvLen != chunkLen:
raise newException(ProtocolError, "invalid chunk read")
await send(b, addr session.buffer[0], recvLen)
inc(total, recvLen)
return total
proc passClientChunks(session: Snoop): Future[int] =
passChunks(session, session.client, session.daemon)
proc passErrorDaemonError(session: Snoop) {.async.} =
let
typ = await passDaemonString(session)
assert typ == "Error"
let
lvl = await passDaemonWord(session)
name = await passDaemonString(session)
msg = passDaemonString(session)
havePos = await passDaemonWord(session)
assert havePos == 0
let
nrTraces = await passDaemonWord(session)
for i in 1..nrTraces:
let havPos = await passDaemonWord(session)
assert havPos == 0
let msg = await passDaemonString(session)
proc passDaemonFields(session: Snoop): Future[Fields] {.async.} =
let count = await passDaemonWord(session)
var fields = newSeq[Field](count)
for i in 0..<count:
let typ = await passDaemonWord(session)
case typ
of 0:
let num = await passDaemonWord(session)
fields[i] = Field(orKind: FieldKind.int, int: int num)
of 1:
let str = await passDaemonString(session)
fields[i] = Field(orKind: FieldKind.string, string: str)
else:
raiseAssert "unknown field type " & $typ
return fields
proc passWork(session: Snoop) {.async.} =
while true:
let word = await passDaemonWord(session)
case word
of STDERR_WRITE:
discard await passDaemonString(session)
of STDERR_READ:
discard await passClientString(session)
of STDERR_ERROR:
assert session.version.minor >= 26
await passErrorDaemonError(session)
of STDERR_NEXT:
let s = await passDaemonString(session)
of STDERR_START_ACTIVITY:
var act: ActionStart
act.id = BiggestInt(await passDaemonWord(session))
act.level = BiggestInt(await passDaemonWord(session))
act.`type` = BiggestInt(await passDaemonWord(session))
act.text = await passDaemonString(session)
act.fields = await passDaemonFields(session)
act.parent = BiggestInt(await passDaemonWord(session))
of STDERR_STOP_ACTIVITY:
var act: ActionStop
act.id = BiggestInt(await passDaemonWord(session))
of STDERR_RESULT:
var act: ActionResult
act.id = BiggestInt(await passDaemonWord(session))
act.`type` = BiggestInt(await passDaemonWord(session))
act.fields = await passDaemonFields(session)
of STDERR_LAST:
break
else:
raise newException(ProtocolError, "unknown work verb " & $word)
#[
proc fromClient(miss: var Missing; socket: AsyncSocket) {.async.} =
result.targets = await passClientStringSet(session)
proc fromDaemon(miss: var Missing; socket: AsyncSocket) {.async.} =
miss.willBuild = await passDaemonStringSet(session)
miss.willSubstitute = await passDaemonStringSet(session)
miss.unknown = await passDaemonStringSet(session)
miss.downloadSize = BiggestInt await passDaemonWord(session)
miss.narSize = BiggestInt await passDaemonWord(session)
]#
proc loop(session: Snoop) {.async.} =
var chunksTotal: int
try:
while not session.client.isClosed:
let wop = await passClientWord(session)
case wop
of wopIsValidPath:
let path = await passClientString(session)
stderr.writeLine "wopIsValidPath ", path
await passWork(session)
let word = await passDaemonWord(session)
of wopAddToStore:
assert session.version.minor >= 25
let
name = await passClientString(session)
caMethod = await passClientString(session)
refs = await passClientStringSet(session)
repairBool = await passClientWord(session)
stderr.writeLine "wopAddToStore ", name
let n = await passClientChunks(session)
inc(chunksTotal, n)
await passWork(session)
let info = await passDaemonValidPathInfo(session, true)
of wopAddTempRoot:
let path = await passClientString(session)
stderr.writeLine "wopAddTempRoot ", path
await passWork(session)
discard await passDaemonWord(session)
of wopAddIndirectRoot:
let path = await passClientString(session)
stderr.writeLine "wopAddIndirectRoot ", path
await passWork(session)
discard await passDaemonWord(session)
of wopSetOptions:
discard passClientWord(session) # keepFailed
discard passClientWord(session) # keepGoing
discard passClientWord(session) # tryFallback
discard passClientWord(session) # verbosity
discard passClientWord(session) # maxBuildJobs
discard passClientWord(session) # maxSilentTime
discard passClientWord(session) # useBuildHook
discard passClientWord(session) # verboseBuild
discard passClientWord(session) # logType
discard passClientWord(session) # printBuildTrace
discard passClientWord(session) # buildCores
discard passClientWord(session) # useSubstitutes
assert session.version.minor >= 12
let overrides = await passClientStringMap(session)
await passWork(session)
of wopQueryPathInfo:
assert session.version >= 17
let path = await passClientString(session)
stderr.writeLine "wopQueryPathInfo ", path
await passWork(session)
let valid = await passDaemonWord(session)
if valid != 0:
var info = await passDaemonValidPathInfo(session, false)
info.path = path
stderr.writeLine "wopQueryPathInfo ", $info
of wopQueryMissing:
assert session.version >= 30
var miss: Missing
miss.targets = await passClientStringSeq(session)
await passWork(session)
miss.willBuild = await passDaemonStringSet(session)
miss.willSubstitute = await passDaemonStringSet(session)
miss.unknown = await passDaemonStringSet(session)
miss.downloadSize = BiggestInt await passDaemonWord(session)
miss.narSize = BiggestInt await passDaemonWord(session)
stderr.writeLine "wopQueryMissing ", $miss
of wopBuildPathsWithResults:
assert session.version >= 34
let
drvs = await passClientStringSeq(session)
buildMode = await passClientWord(session)
stderr.writeLine "wopBuildPathsWithResults drvs ", $drvs
await passWork(session)
let count = await passDaemonWord(session)
for _ in 1..count:
let
path = await passDaemonString(session)
status = await passDaemonWord(session)
errorMsg = await passDaemonString(session)
timesBUild = await passDaemonWord(session)
isNonDeterministic = await passDaemonWord(session)
startTime = await passDaemonWord(session)
stopTime = await passDaemonWord(session)
outputs = await passDaemonStringMap(session)
else:
stderr.writeLine "unknown worker op ", wop.int
break
except ProtocolError as err:
stderr.writeLine "connection terminated"
stderr.writeLine "chunk bytes transfered: ", formatSize(chunksTotal)
finally:
close(session.daemon)
close(session.client)
proc handshake(listener: AsyncSocket): Future[Snoop] {.async.} =
## Take the next connection from `listener` and return a `Session`.
let session = Snoop(buffer: newSeq[Word](1024)) # 8KiB
session.client = await listener.accept()
session.daemon = newAsyncSocket(
domain = AF_UNIX,
sockType = SOCK_STREAM,
protocol = cast[Protocol](0),
buffered = false,
)
await connectUnix(session.daemon, daemonSocketPath())
let clientMagic = await passClientWord(session)
if clientMagic != WORKER_MAGIC_1:
raise newException(ProtocolError, "invalid protocol magic")
let daemonMagic = await passDaemonWord(session)
let daemonVersion = await passDaemonWord(session)
session.version = Version(await passClientWord(session))
if session.version < PROTOCOL_VERSION:
raise newException(ProtocolError, "obsolete protocol version")
assert session.version.minor >= 14
discard await(passClientWord(session))
# obsolete CPU affinity
assert session.version.minor >= 11
discard await(passClientWord(session))
# obsolete reserveSpace
assert session.version.minor >= 33
let daemonVersionString = await passDaemonString(session)
assert daemonVersionString == $store.nixVersion
await passWork(session)
return session
proc emulateSocket*(path: string) {.async, gcsafe.} =
let listener = newAsyncSocket(
domain = AF_UNIX,
sockType = SOCK_STREAM,
protocol = cast[Protocol](0),
buffered = false)
bindUnix(listener, path)
listen(listener)
stderr.writeLine "listening on ", path
while not listener.isClosed:
try:
let session = await handshake(listener)
assert not session.isNil
asyncCheck loop(session)
except ProtocolError:
close(session)
finally:
close(session)

View File

@ -5,7 +5,7 @@ import
type
Eval* {.preservesRecord: "eval".} = object
`expr`*: string
`options`*: Table[Symbol, Preserve[void]]
`path`*: string
`result`*: Preserve[void]
AttrSet* = Table[Symbol, Preserve[void]]