Skip to content

Architecture Intro

Ben Baron edited this page Aug 9, 2013 · 1 revision

If you're interested in contributing code to WaveBox, please read this quick architecture overview. It explains how the application is structured and certain design decisions.

While it's coded in C#, we're targeting the Mono 3 runtime, not necessarily .NET. For all intents and purposes, these are the same, but we do occasionally use some Mono additions (like dllmaps for different platforms).

Basically the project it split into 2 assemblies: Core and Server.

Core contains the data model and basically any logic that isn't specific to the actual server part (i.e. could also be used in a client).

This is:

  • Model objects (Song, Album, etc) that are basically just a set of properties with maybe a few relevant methods
  • Repository objects (SongRepository, AlbumRepository, etc) which contain only database access methods for those model objects
  • ApiResponse objects which are small model objects used by the Api handlers (more on those in a bit) to convert to JSON and return to the client
  • And a few Utility/Extension classes

Server contains everything relevant to the actual API and media server.

This is:

  • The WaveBoxMain and WaveBoxService classes which are the entry points (we use the Mono service wrapper to allow for it to be installed as a daemon on Linux or an actual Windows service on Windows — however it also works as a standalone terminal application on Windows).
  • Services, which are dynamically loaded services to handle things like device syncing, http serving, nat, zeroconf, etc. These are created by simply implementing the IService interface and then enabling the service by name in the wavebox.conf file
  • ApiHandler, which are dynamically loaded (any class implementing IApiHandler) and handle each API call. So one ApiHandler class corresponds to each API entry point. They generally call some methods on the data model objects or repositories in the Core library, create an ApiResponse model object, serialize to JSON, and return.
  • Transcoding, which handles the various media format transcoding that is supported
  • Folder scanning, which keeps the media collection up to date
  • And some utility and extension classes

Couple of things to be aware of:

  1. The Core assembly is re-used in a range of clients that we're building for iOS, Android, Mac, Windows, and Linux, using Xamarin's tools. We're currently refactoring the Core assembly to remove any non PCL compliant namespaces, but that is not complete yet.

  2. We're currently refactoring the whole project to use the Ninject IoC container for DI. You'll see some places where this is completed (like the Repository classes) and others where it isn't and the Ninject Kernel is being references statically. We're working towards full DI.

  3. We're still refactoring the ApiHandlers. We're working to decouple the HttpProcessor class from the handlers.

  4. We're currently not using async and await much in the Core and Server as it wasn't supported in Mono 2. It is supported in Mono 3, so we'll be using more of that in the future.

  5. Our database schema is a bit unusual. Instead of using primary keys for each table, we use a single auto-incrementing value for all (actually most) ids. This allows for API calls that can accept an id for different object types to take only an id and know what to do, or for things like a playlist which may take songs and videos to be able to use just a simple list of integers. So you'll see that the db tables have unique indexed fields for id rather than primary key.

  6. Another unusual thing about the design is that the native clients are meant to download the server's actual sqlite database, to run local queries rather than using the server (the HTML5 client uses the API calls only). This allows for a lot of otherwise impossible features, like playlist creation in offline mode, etc. So you'll see the code we use to do db backups and we keep a query log to allow the clients to apply db changes without completely re-syncing.

  7. We don't currently have any unit or integration tests, this is a big problem and if you're experienced in that area, this would be the most useful contribution we could get right now. Since the project was not built with unit testing in mind, the best bang for the buck at the beginning would probably be to write integration tests that actually do API calls on a running server using a known library, parse the JSON, and check for expected responses. That way all systems from the back end to the user are tested in one shot, rather than doing integration tests on just the ApiHandler response objects or something. I'm pretty sure we could do this using C# and NUnit, but if you have any suggestions they would be most welcome.

  8. Another big area that we could use some help is performance and memory profiling. If you're experienced in this area and could help speed up our scanning process or improve any other CPU/Disk/Memory intensive area, that would be awesome.

Clone this wiki locally