For a long time I wanted the ability to show my Todos from Things to show outside my Apple devices. Since it can sync I went and searched for some packages that can do that. I found some examples on how to do it. I did reverse engineer the rest of the properties beeing send from the server while syncing.

I have a MagicMirror-Display hanging on my wall at home so naturally I wanted to display the todos on it and went and made a custom_module for it. Since I like Rust and wanted also to play with it. Therefor I created a hybird module where part was implemented in Rust and the bridge to MagicMirror was provided by Node.js.

If you want to try it out head over to the GitHub project.

Technical Stuff

Code

To create a binding between Rust and Node I used neon. I was lazy so I tried using neon-serde which makes it really easy to create a interface between rust and node. I provides macros and some other niceties to create the interface more idiomatically.

This looks nice:

export! {
  fn getTodayEntries(dirname: String) -> Vec<Task> {
    load_env(&dirname);
    get_today_tasks().unwrap()
  }
  fn getTomorrowEntries(dirname: String) -> Vec<Task> {
    load_env(&dirname);
    get_tomorrow_tasks().unwrap()
  }

  fn updateDB(dirname: String) -> u32 {
      load_env(&dirname);
      update_db().unwrap()
  }
  fn getInboxEntries(dirname: String) -> Vec<Task> {
    load_env(&dirname);
    get_inbox_tasks().unwrap()
  }
}

Cross compile

As this project now needed to be compiled and I didn't want to wait for 30 min while it compiles on the raspberry pi, I had to find a way to cross-compile on my mac to arm/linux. I could have used "native" crosscompilers like crosstool-ng, but I wanted to keep my filesystem as clean as possible, so I decided to go with a docker-based approach. Nearly everything was provided by this docker-image. I only had to make it possible to compile rust with neon and have node available. That's why I based it on the node image in this commit. After that I was able to cross-compile from my Mac (macOS; X64) to the raspberry pi (Raspian; ARM).

In the process of making it work I ran into two errors:

  1. Neon-serde was not able to compile for a target which was not 64-bit. This shows that nearly nobody (using rust) is working with 32-bit only systems anymore. I created a workaround for me which was in the end superseeded by chaning the dependency.
  2. neon did not recognise / use the build target set for cargo (CARGO_BUILD_TARGET). But a PR was merged soon after.

That's what happens when working on the edge of what is possible.

Debugging

While I was working on making it work in the first-place I found the following topics / links interesting for finding help on my problems.

  • Module did not self-register
    • https://github.com/neon-bindings/neon/issues/362#issuecomment-425814276
      • https://github.com/katyo/ledb/commit/0e7fbce88be5471bf52bcf69b5824d2f90cc6baa
      • https://github.com/katyo/neon/commit/3319c6ce54ba67451b236901ca0669397d68c659
  • Cross compiling gist
    • https://gist.github.com/crabtw/5150198
  • Codegen options
    • https://doc.rust-lang.org/rustc/codegen-options/index.html
  • cross compile node gyp
    • https://stackoverflow.com/questions/6696222/cross-compiling-with-gyp -common|optimizers|params|target|warnings|[^]{joined|separate|undocumented