diff --git a/Tupfile b/Tupfile index 9368191..28c450e 100644 --- a/Tupfile +++ b/Tupfile @@ -1,3 +1,2 @@ include_rules -: |> !nim_lk |> | ./ : lock.json |> !nim_cfg |> | ./ diff --git a/lock.json b/lock.json index 21f963e..08f588a 100644 --- a/lock.json +++ b/lock.json @@ -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" + } + ] +} diff --git a/nix_actor.nimble b/nix_actor.nimble index 48c8f6e..ad684e5 100644 --- a/nix_actor.nimble +++ b/nix_actor.nimble @@ -1,4 +1,4 @@ -version = "20231009" +version = "20231208" author = "Emery Hemingway" description = "Syndicated Nix Actor" license = "Unlicense" diff --git a/protocol.prs b/protocol.prs index 335f549..2502aed 100644 --- a/protocol.prs +++ b/protocol.prs @@ -10,7 +10,7 @@ Realise = . Instantiate = . -Eval = . +Eval = . Narinfo = . diff --git a/shell.nix b/shell.nix index 656b039..75d225f 100644 --- a/shell.nix +++ b/shell.nix @@ -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; } diff --git a/src/nix_actor.nim b/src/nix_actor.nim index a5a6bfc..b4e58e9 100644 --- a/src/nix_actor.nim +++ b/src/nix_actor.nim @@ -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() diff --git a/src/nix_actor.nim.cfg b/src/nix_actor.nim.cfg deleted file mode 100644 index 1dcd32b..0000000 --- a/src/nix_actor.nim.cfg +++ /dev/null @@ -1 +0,0 @@ -backend:cpp diff --git a/src/nix_actor/daemons.nim b/src/nix_actor/daemons.nim index 3bc5591..8e3a7fb 100644 --- a/src/nix_actor/daemons.nim +++ b/src/nix_actor/daemons.nim @@ -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 ]> - 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) diff --git a/src/nix_actor/nix_api.nim b/src/nix_actor/nix_api.nim new file mode 100644 index 0000000..2093773 --- /dev/null +++ b/src/nix_actor/nix_api.nim @@ -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]) + diff --git a/src/nix_actor/nix_api_expr.nim b/src/nix_actor/nix_api_expr.nim new file mode 100644 index 0000000..d3cd6cc --- /dev/null +++ b/src/nix_actor/nix_api_expr.nim @@ -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.} + diff --git a/src/nix_actor/nix_api_store.nim b/src/nix_actor/nix_api_store.nim new file mode 100644 index 0000000..6e5ccfe --- /dev/null +++ b/src/nix_actor/nix_api_store.nim @@ -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.} + diff --git a/src/nix_actor/nix_api_util.nim b/src/nix_actor/nix_api_util.nim new file mode 100644 index 0000000..2a78428 --- /dev/null +++ b/src/nix_actor/nix_api_util.nim @@ -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.} diff --git a/src/nix_actor/nix_api_value.nim b/src/nix_actor/nix_api_value.nim new file mode 100644 index 0000000..057f638 --- /dev/null +++ b/src/nix_actor/nix_api_value.nim @@ -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".} diff --git a/src/nix_actor/old.nim b/src/nix_actor/old.nim new file mode 100644 index 0000000..78ef762 --- /dev/null +++ b/src/nix_actor/old.nim @@ -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..= 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..= 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) diff --git a/src/nix_actor/protocol.nim b/src/nix_actor/protocol.nim index 6f31627..4a485f7 100644 --- a/src/nix_actor/protocol.nim +++ b/src/nix_actor/protocol.nim @@ -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]]