#include "serialise.hh" #include "path-with-outputs.hh" #include "store-api.hh" #include "build-result.hh" #include "worker-protocol.hh" #include "worker-protocol-impl.hh" #include "archive.hh" #include "path-info.hh" #include #include namespace nix { /* protocol-specific definitions */ BuildMode WorkerProto::Serialise::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { auto temp = readNum(conn.from); switch (temp) { case 0: return bmNormal; case 1: return bmRepair; case 2: return bmCheck; default: throw Error("Invalid build mode"); } } void WorkerProto::Serialise::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const BuildMode & buildMode) { switch (buildMode) { case bmNormal: conn.to << uint8_t{0}; break; case bmRepair: conn.to << uint8_t{1}; break; case bmCheck: conn.to << uint8_t{2}; break; default: assert(false); }; } std::optional WorkerProto::Serialise>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { auto temp = readNum(conn.from); switch (temp) { case 0: return std::nullopt; case 1: return { Trusted }; case 2: return { NotTrusted }; default: throw Error("Invalid trusted status from remote"); } } void WorkerProto::Serialise>::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const std::optional & optTrusted) { if (!optTrusted) conn.to << uint8_t{0}; else { switch (*optTrusted) { case Trusted: conn.to << uint8_t{1}; break; case NotTrusted: conn.to << uint8_t{2}; break; default: assert(false); }; } } std::optional WorkerProto::Serialise>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { auto tag = readNum(conn.from); switch (tag) { case 0: return std::nullopt; case 1: return std::optional{std::chrono::microseconds(readNum(conn.from))}; default: throw Error("Invalid optional tag from remote"); } } void WorkerProto::Serialise>::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const std::optional & optDuration) { if (!optDuration.has_value()) { conn.to << uint8_t{0}; } else { conn.to << uint8_t{1} << optDuration.value().count(); } } DerivedPath WorkerProto::Serialise::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { auto s = readString(conn.from); if (GET_PROTOCOL_MINOR(conn.version) >= 30) { return DerivedPath::parseLegacy(store, s); } else { return parsePathWithOutputs(store, s).toDerivedPath(); } } void WorkerProto::Serialise::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const DerivedPath & req) { if (GET_PROTOCOL_MINOR(conn.version) >= 30) { conn.to << req.to_string_legacy(store); } else { auto sOrDrvPath = StorePathWithOutputs::tryFromDerivedPath(req); std::visit(overloaded { [&](const StorePathWithOutputs & s) { conn.to << s.to_string(store); }, [&](const StorePath & drvPath) { throw Error("trying to request '%s', but daemon protocol %d.%d is too old (< 1.29) to request a derivation file", store.printStorePath(drvPath), GET_PROTOCOL_MAJOR(conn.version), GET_PROTOCOL_MINOR(conn.version)); }, [&](std::monostate) { throw Error("wanted to build a derivation that is itself a build product, but protocols do not support that. Try upgrading the Nix on the other end of this connection"); }, }, sOrDrvPath); } } KeyedBuildResult WorkerProto::Serialise::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { auto path = WorkerProto::Serialise::read(store, conn); auto br = WorkerProto::Serialise::read(store, conn); return KeyedBuildResult { std::move(br), /* .path = */ std::move(path), }; } void WorkerProto::Serialise::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const KeyedBuildResult & res) { WorkerProto::write(store, conn, res.path); WorkerProto::write(store, conn, static_cast(res)); } BuildResult WorkerProto::Serialise::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) { BuildResult res; res.status = static_cast(readInt(conn.from)); conn.from >> res.errorMsg; if (GET_PROTOCOL_MINOR(conn.version) >= 29) { conn.from >> res.timesBuilt >> res.isNonDeterministic >> res.startTime >> res.stopTime; } if (GET_PROTOCOL_MINOR(conn.version) >= 37) { res.cpuUser = WorkerProto::Serialise>::read(store, conn); res.cpuSystem = WorkerProto::Serialise>::read(store, conn); } if (GET_PROTOCOL_MINOR(conn.version) >= 28) { auto builtOutputs = WorkerProto::Serialise::read(store, conn); for (auto && [output, realisation] : builtOutputs) res.builtOutputs.insert_or_assign( std::move(output.outputName), std::move(realisation)); } return res; } void WorkerProto::Serialise::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const BuildResult & res) { conn.to << res.status << res.errorMsg; if (GET_PROTOCOL_MINOR(conn.version) >= 29) { conn.to << res.timesBuilt << res.isNonDeterministic << res.startTime << res.stopTime; } if (GET_PROTOCOL_MINOR(conn.version) >= 37) { WorkerProto::write(store, conn, res.cpuUser); WorkerProto::write(store, conn, res.cpuSystem); } if (GET_PROTOCOL_MINOR(conn.version) >= 28) { DrvOutputs builtOutputs; for (auto & [output, realisation] : res.builtOutputs) builtOutputs.insert_or_assign(realisation.id, realisation); WorkerProto::write(store, conn, builtOutputs); } } ValidPathInfo WorkerProto::Serialise::read(const StoreDirConfig & store, ReadConn conn) { auto path = WorkerProto::Serialise::read(store, conn); return ValidPathInfo { std::move(path), WorkerProto::Serialise::read(store, conn), }; } void WorkerProto::Serialise::write(const StoreDirConfig & store, WriteConn conn, const ValidPathInfo & pathInfo) { WorkerProto::write(store, conn, pathInfo.path); WorkerProto::write(store, conn, static_cast(pathInfo)); } UnkeyedValidPathInfo WorkerProto::Serialise::read(const StoreDirConfig & store, ReadConn conn) { auto deriver = readString(conn.from); auto narHash = Hash::parseAny(readString(conn.from), HashAlgorithm::SHA256); UnkeyedValidPathInfo info(narHash); if (deriver != "") info.deriver = store.parseStorePath(deriver); info.references = WorkerProto::Serialise::read(store, conn); conn.from >> info.registrationTime >> info.narSize; if (GET_PROTOCOL_MINOR(conn.version) >= 16) { conn.from >> info.ultimate; info.sigs = readStrings(conn.from); info.ca = ContentAddress::parseOpt(readString(conn.from)); } return info; } void WorkerProto::Serialise::write(const StoreDirConfig & store, WriteConn conn, const UnkeyedValidPathInfo & pathInfo) { conn.to << (pathInfo.deriver ? store.printStorePath(*pathInfo.deriver) : "") << pathInfo.narHash.to_string(HashFormat::Base16, false); WorkerProto::write(store, conn, pathInfo.references); conn.to << pathInfo.registrationTime << pathInfo.narSize; if (GET_PROTOCOL_MINOR(conn.version) >= 16) { conn.to << pathInfo.ultimate << pathInfo.sigs << renderContentAddress(pathInfo.ca); } } WorkerProto::ClientHandshakeInfo WorkerProto::Serialise::read(const StoreDirConfig & store, ReadConn conn) { WorkerProto::ClientHandshakeInfo res; if (GET_PROTOCOL_MINOR(conn.version) >= 33) { res.daemonNixVersion = readString(conn.from); } if (GET_PROTOCOL_MINOR(conn.version) >= 35) { res.remoteTrustsUs = WorkerProto::Serialise>::read(store, conn); } else { // We don't know the answer; protocol to old. res.remoteTrustsUs = std::nullopt; } return res; } void WorkerProto::Serialise::write(const StoreDirConfig & store, WriteConn conn, const WorkerProto::ClientHandshakeInfo & info) { if (GET_PROTOCOL_MINOR(conn.version) >= 33) { assert(info.daemonNixVersion); conn.to << *info.daemonNixVersion; } if (GET_PROTOCOL_MINOR(conn.version) >= 35) { WorkerProto::write(store, conn, info.remoteTrustsUs); } } }