Devious Fish
Developing pianod2

Developing pianod2

This file is intentionally not included with releases. It is only available from the pianod2 SVN respository.

This file outlines creating a development area for pianod2. If you just want to install pianod2, download a tarball and see the INSTALL file instead.

Setting Up

Prerequisites

  • make
  • C, C++ compilers; also Objective C compiler if on OS X/macOS
  • m4
  • automake, autoconf, and Perl
  • Node.js (nodejs and npm (node package manager))
  • ksh (the genuine article, not pdksh; ideally ksh’93)
  • Java (ugh, I know, but Validator.nu is written in it.)
  • HTML Tidy (a recent one–I have 5.7.3. The 2009 versions supplied by some package managers won’t cut it.)

Installing Components

Install Node.js modules:

     # Typescript compiler
        sudo npm install -g typescript

        # Type definitions are used by the TypeScript compiler to
        # validate the code.

        # Note: Currently we require @types/jquery v. 2.0.39 (look in the
        # package.json file for the version number).  There's an issue
        # with JQuery trying to use `Iterable<type>`, but not knowing what
        # `Iterable<>` is.  There are 101 answers on the web for this,
        # all different.  If someone wants to look into this, it would be
        # great.  I think we may need a `--lib` when compiling, but I'm
        # unclear exactly what it wants.  Until fixed, we're out of
        # luck on the tightened-up v. 3.2+ jquery definitions.
        sudo npm install -g @types/jquery@2.0.39

        sudo npm install -g @types/assert
        sudo npm install -g @types/node

        # These next node things perform required transforms.
        sudo npm install -g browserify
        sudo npm install -g browserify-shim
        # Currently not using unassertify; doesn't work right.
        # If we ever fix it: sudo npm install -g unassertify
        sudo npm install -g uglify-js

        # Install Validator.nu HTML validator
        sudo npm install -g vnu-jar

As a bonus, browserify installs itself with a shebang of #!/usr/bin/env node, even though node switched to nodejs years ago to avoid a naming collision with other packages. Depending on your installation, you may need to change it to #!/usr/bin/env nodejs. (Goddess I hate depending on Node.js!)

Note: In the future, you can update your nodejs installation by sudo npm update -g. Note, however, this might update and break the JQuery types if we haven’t solved that yet.

Setting up a build area

Get the source code from SVN. If you’re just submitting minor fixes, you may work directly on the trunk.

     svn co svn://svn.deviousfish.com/trunk your_local_dirname

If you’re working on something large, like a new source, please create a branch and we’ll integrate it back into the trunk when it’s ready.

     svn copy svn://svn.deviousfish.com/trunk svn://svn.deviousfish.com/branches/name_feature
        svn co svn://svn.deviousfish.com/branches/name_feature your_local_dirname

To prepare the directory for use:

     autoreconf -i
        autoreconf
        ./configure --enable-debug [insert your configure options here]

Before proceding, check that configure is building with what you expect. Add packages or switches as necessary.

     make
        make check

Running make check is especially important as a developer: you don’t want to troubleshoot your code trying to find something that was already broken.

Integration test Suite

You can run the test suite directly:

     ./pianod_unittest

There are 5 environment variables used by the unit test script for audio output settings, should the default outputs not be right:

  • PIANOD_UNITTEST_AUDIO_LIBRARY
  • PIANOD_UNITTEST_AUDIO_DRIVER
  • PIANOD_UNITTEST_AUDIO_ID
  • PIANOD_UNITTEST_AUDIO_OPTIONS
  • PIANOD_UNITTEST_AUDIO_SERVER

To add tests, follow the formula of the test_something functions. The driver loop uses introspection find and execute all tests, and report the the results.

Session and daemon transcripts are reported when failures are encountered, or when the -v option is given.

Manual testing

The executable is in the src directory. It expects the client to be in its installed location (often /usr/local/share/pianod/html). Use the -c option point it to your build area:

     src/pianod -c `pwd`/html

Submitting code

You’ll need commit rights. Mail a preferred username & password to perette@deviousfish.com.

Before committing code to the trunk, notify us what’s coming on the pianod mailing list. For small things, include the patch (from svn diff). svn may force you to update before commit: svn update. In the unlikely event of conflicts with other changes, you’ll need to resolve them. When ready: svn commit.

For larger changes, commit the changes to your branch, then notify the mailing list the branch is ready for review. Once a second pair of eyes has reviewed it, it will be reintegrated into the trunk. Do not use the branch for futher work except bug fixes prior to reintegration; after reintegration, the branch is deleted. Create a new branch from the trunk if required.

About The Code

The Daemon

The daemon is found in the src directory.

  • rapidjson is not presently used. It’s fair game to use, but it’s an external library, so do not customize it. Make sure bugs get fixed in upstream code.
  • rapidxml is an external project. Do not customize it. Make sure bugs get fixed in upstream code.
  • libfootball, in C99, is the communication layer code.
  • mediaunits/pandora/libpiano is from pianobar. Do not customize it. If bugs are found, or it breaks down due to protocol changes, replace it with an updated version from pianobar.

..If anyone wanted to take on rewriting the Pandora implementation to do it in our own code, and drop libpiano, that might be kosher. The risk is we inherit having to maintain it.

  • mediaunits/audio contains the bridges to various audo decoding and audio output code.
  • mediaunits/metadata contains the bridges to various tag/ID3 extracting code.
  • The rest of the mediaunits directories are the sources.
  • mediaunits/sources.cpp provides source registration at startup.

Coding Standards

Write good code. Don’t just write the expected case; think about what can go wrong, and ensure it’ll be handled correctly. Test your stuff, and run it through valgrind. Add test cases where possible.

Use assertions to check expectations and enforce contracts.

Take time to pick clear variable and function names. Although it’s said the length of a name is proportional to its scope, that doesn’t excuse many 1-letter names. Use names that provide context to the next guy.

Use const or its equivalent whenever you can.

Do not use “Hungarian notation.”

If you encounter a piece of code that doesn’t follow the standards here, use your judgement. If you’re only making small revisions, it may be better to follow the existing style. If the out-of-policy parts are small, consider conforming them.

C99

Use all_lowercase_snake_case for function_names, variables (both global and automatic), and parameter_names.

typedefs prefer LeadingCapital CamelCase.

When creating a typedef for a struct or union, assign the struct an all-underscore name ending with _t (some compilers yield better warnings):

     typedef struct my_struct_t {
        int my_field;
    } MyStruct;

enum values should USE ALL CAPS. (But prefer C++ enum classes, mentioned below).

C++11

If you’re new to C++, bone up on RAII. It’s really important.

Non-class functions, and static class members, all variables and all parameters should use all lowercase snake_case.

Use enum class instead of old-style enum. The enumeration type name and enumeration values should be LeadingCapital CamelCase.

Namespace, class, structure, and template names should use LeadingCapital CamelCase.

Use operator overloading with care: use it where appropriate, but don’t go crazy; it can make code illegible. If having both forms (operator and function) make the code more legible, depending on context, considering defining one as an inline function wrapping the other.

Google hard, but ask questions when you need. Study the issue so you can ask the question effective. And don’t be offended when asked a question. Take the time to answer well; half-assed answers are a waste of your time, and the person who gets it.

Read that last one again, because crappy questions cause answer apathy, which disincents us from asking useful ones. Let’s not go down that path, and instead communicate effectively. It makes it funner for all of us.

Code Formatting

Please try to follow the existing style. Use:

  • attached opening braces (aspell: –style=attached), not on a separate line.
  • Braces:
    • go on the same line as whatever they are defining/structuring. (aspell: –style-attached) Exception: when a case needs braces, they go on the next line.
    • are optional in loops and ifs, but if any case of an if requires braces, wrap all of them.
    • should be used when encompasing another conditional/loop.
    • the closing brace goes on its own line
  • Spaces:
    • are used for indentation, not tabs (–indent=spaces=4).
    • are placed around infix operators (but not prefix/postfix).
    • are included after function names in calls, declarations and definitions.
  • Indent:
    • Four spaces per level.
    • For now, the bodies of namespaces are indented. (–indent-namespaces)
    • Case labels are indented 4 spaces, with their statements indented 4 more spaces (–indent-switches). (If case bodies require braces, these go on the same line as the case).
  • For multi-line statements:
    • indent continued conditionals a little more than the subsequent body to create a distinction (–min-conditional-indent=8).
    • indent continued assignments to the characters 1 space past =, to align with the assigned value. Alternately, if the assigned value is a function call, align parameters with its parentheses (below).
    • indent continued function call parameters with the right side of the open-parenthesis. (–max-continuation-indent=40)

Screens are big now, so don’t spare the whitespace if it helps legibility or comprehension. Try to keep things uniform, but use good judgement; if there’s a good reason to break from the usual style, that’s okay.

The Clients

The client, console, and viewer are in the html subdirectory, with 3 branches off that: pages (the HTML source), locale (text for various languages), and scripts (client-side TypeScript and JavaScript).

pages

There are 3 .web files, one for each client: client, console, and viewer. The console and viewer are self-contained. To keep things manageable, each of the client’s panes has its own .m4 source file; index.web pulls these in to assemble the completed client.

Clients can be compiled in regular mode and compressed mode. In regular mode, clients reference their supporting JavaScript libraries in the scripts directory, and expect a local JQuery. In compressed mode, JavaScript libraries are expected to be co-located in the directory with the HTML, and a Google-hosted JQuery is used.

Page compilation happens in 3 phases:

  1. Use m4 to convert source to HTML.
  2. Use tidy to clean up the results.
  3. Validate the resulting HTML.

If successful, the resulting page is technically valid but filled with language keys. These are replaced by the Makefiles in locale.

locale

Contains the language-specific text for the clients. Each language has a phrases.<language>.lang file with key-to-text dictionary such as:

HEADING_ACTION                  Actions
PROMPT_CONFIRM_DELETE           Are you sure you want to delete %1$s?
PIANOD_LICENSE                  Released under the MIT license.

The locale Makefile uses m4 to substitute the keys into the client HTML in the pages directory.

There is also a translate.js.m4 file. It contains a list of the translation keys utilized by client’s JavaScript using JSON notation. The Makefile uses m4 to insert keys, create language-specific translate.js files.

scripts

The client scripts are mostly written in TypeScript, which is transpiled into JavaScript. TypeScript has a cleaner syntax, and in the compilation process, the typescript compiler tsc gives lots of lovely warnings and errors when we mere humans try to do something stupid.

  • communication.ts contains the protocol code used by all clients.
  • console.ts and viewer.ts are for the respective clients.
  • view.ts and comm.ts provide infrastructure for the main client views.
  • tableview.js provides infrastructure for a few of the views.
  • ratings.js contains code for the client’s star ratings widget.
  • The rest of the files correspond to each pane/view in the client.

Functions are documented with docucomments in the manner of the daemon.

miniscripts

When making the clients for distribution, a fourth directory is created. miniscripts contains a copy of scripts, but with assertions stripped from the code. This is recompiled, and the resulting code copied into the parent html directory.

miniscripts is removed by make clean.