On rewriting Go code in C++

On rewriting tooling in C++

I wrote some tooling in C++ that reimplements some functionality I had originally written in Go, mostly to build more C++ skills relevant to work. They're similar line counts:

+--------------+-------+-------+---------+------+
| Language     | files | blank | comment | code |
+--------------+-------+-------+---------+------+
| C++          |     4 |    91 |      85 |  406 |
| C/C++ Header |     3 |    24 |      63 |   31 |
+--------------+-------+-------+---------+------+
| C++ total    |     7 |   115 |     148 |  437 |
+--------------+-------+-------+---------+------+
| Go           |     7 |    68 |      33 |  317 |
+--------------+-------+-------+---------+------+

A little bit more code, most because my flags and configuration packages are more verbose in C++ than in Go. One area of illustration: uploading files.

In Go:

func (pkg Debpack) Put(debFile string) error {
        url := pkg.URL("upload")

        file, err := os.Open(debFile)
        if err != nil {
                return err
        }
        defer file.Close()

        client := http.DefaultClient
        req, err := http.NewRequest(http.MethodPut, url, file)
        if err != nil {
                return err
        }
        req.SetBasicAuth(config.Get("username"), config.Get("password"))

        resp, err := client.Do(req)
        defer resp.Body.Close()
        if err != nil {
                return err
        }

        result := http.StatusText(resp.StatusCode)

        switch resp.StatusCode {
        case 201:
                result = "package created"
        case 400:
                result = "bad name, version, distribution, component or arch (duplicate?)"
        case 409:
                result = "duplicate package"
        }
        fmt.Printf("%s: %d %s\n", filepath.Base(debFile), resp.StatusCode, result)

        return nil
}

and in C++:

bool
putDebian(std::vector<std::string> args)
{
        auto ok = true;
        for (auto &arg: args) {
                auto url    = debianEndpoint("upload");
                auto result = PutFile(url, arg);
                std::cout << "\t[*] PUT " << std::filesystem::path(arg).filename() << ": ";
                std::cout << ResultToString(result) << "\n";
                ok &= ResultSuccess(result);
        }

        return ok;
}

and:

Result
PutFile(std::string url, std::string path)
{
        const curlpp::Cleanup clearerr;
        static std::string userPass;
        auto verbose = false;
        curlpp::Easy request;

        if (scsl::SimpleConfig::GetGlobal("verbose") == "true") {
                verbose = true;
        }

        if (userPass.empty()) {
                userPass = getUserPass();
        }

        try {
                std::list<std::string> header;
                header.emplace_back("Content-Type: application/octet-stream");

                if (!std::filesystem::exists(path)) {
                        std::cerr << "[!] " << path << " does not exist!\n";
                        return Result::CurlFailed;

                }
                auto fileSize = static_cast<int64_t>(std::filesystem::file_size(path));

                std::ifstream uploadFile(path);
                if (!uploadFile.good()) {
                        std::cerr << "[!] " << path << " does not exist!\n";
                        return Result::CurlFailed;
                }

                request.setOpt(new curlpp::options::Url(url));
                if (verbose) {
                        request.setOpt(new curlpp::options::Verbose(true));
                }
                request.setOpt(new curlpp::options::UserPwd(userPass));
                request.setOpt(new curlpp::Options::ReadStream(&uploadFile));
                request.setOpt(new curlpp::Options::InfileSize(fileSize));
                request.setOpt(new curlpp::Options::Upload(true));
                request.perform();
        } catch (curlpp::LogicError &e) {
                std::cerr << e.what() << "\n";
                return Result::CurlFailed;
        } catch (curlpp::RuntimeError &e) {
                std::cerr << e.what() << "\n";
                return Result::CurlFailed;
        }

        auto httpStatus = curlpp::infos::ResponseCode::get(request);
        switch (httpStatus) {
        case 201:
                return Result::Created;
        case 400:
                return Result::BadPackage;
        case 409:
                return Result::DuplicatePackage;
        default:
                return Result::CurlFailed;
        }
}

kyOSPi//64

Also fired off a background project to work on kOS//pi64.

rpi cm4 dev machine

After realizing I lost all traces of Pious, and re-reading Fantasia and Acorns and Oak Trees, I figured I should kick off a backburner project to write an operating system for the Pi.

Here's what I would like to build: a hypervisor that runs unikernels in "slots." Each unikernel is allocated one or more disk images; each kernel is fully isolated from the others and uses a capability system to assist in enforcing this.

Unlike the previous baking-pi and pious operating systems, this will be a 64-bit operating system. The picture is of a CM4 carrier board, but I ended up scrounging up another pair of Raspberry Pi 4's, one of which went into the rack (where it was originally intended to go), and the other is the kOS//pi64 development board.

The first step is to get a serial console working. The next step is to think about starting to build out a capability system, which will likely start with a virtual memory manager. I'm also going to have to think about getting a network driver going. Gods help me, I'm also thinking about doing some Rust with this. First things first, though. It's also a very slow burn project, and I don't expect to get much done on it very quickly.


Tags: , , , , ,