.. docs/source/developer/design_notes.rst
.. Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
.
This file is part of CamCOPS.
.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see .
Design notes
============
A few design decisions are documented here.
.. contents::
:local:
:depth: 3
See also:
- :ref:`Patient/subject identification `
- :ref:`Security design `
.. _client_sqlcipher_databases:
Client SQLCipher databases
--------------------------
The CamCOPS client uses two databases (typically called `camcops_data.sqlite`
and `camcops_sys.sqlite`), stored in the device’s user-specific private area
(e.g. `~/.local/share/camcops under Linux`). Note that some operating systems
(e.g. Android, iOS) are designed for single-user use and don’t have the concept
of a per-user private area. The ‘data’ database holds user data (patients,
patient data) and the ‘sys’ database contains configuration information, stored
strings, and the like. Both are encrypted with AES-256 via SQLCipher. They use
the same passphrase for user convenience, but different encryption keys
[#sqlcipher]_.
The decision to use two databases rather than one is so that, in emergencies,
the ‘data’ database can be processed (viewed, rescued) without the need to
share the ‘sys’ database and its information. It also simplifies the upload
process a little (as the client can simply upload everything from the ‘data’
database and nothing from the ‘sys’ database).
Inline CSS
----------
The server currently provides CSS inline. It could refer to CSS as files, so
that browsers cache them better. However, inline CSS is still required for PDF
creation, and it’s not clear this is an important performance constraint.
SFTP export
-----------
Not necessary, as one can mount an SFTP directory via NFS, then just export as a
plain file.
Anonymisation
-------------
Proper anonymisation is Somebody Else’s Business; CamCOPS supports convenient
export for subsequent anonymisation (see, for example, CRATE;
https://crateanon.readthedocs.io/).
BLOB handling
-------------
- It's clearly preferable to have BLOBs in the database (rather than on the
filesystem), both on the server and the client (server: easier to manage;
client: within secure encrypted database).
- It's also clearly preferable to have BLOBs in their own table (server:
doesn't slow down all other tables; client: can upload record-by-record for
BLOBs and table-by-table for other things).
- Then, regarding storage/access within the client...
- Writing images to a BLOB is a slow operation: it's the QImage to QByteArray
conversion (and reverse conversion) that's relatively slow. This slows down
rotation. The rotation operation itself, on a QImage, is fast.
- Possible client strategies, then:
- Blob/Field handle QByteArray only; QuImage deals with all the rotation.
Slow for the client but simple.
- Blob/Field deal with a combination of a QByteArray (written as PNG to the
database) and a "rotation" field, and client/server rotate on the fly.
- Should make the client rotation operation fast.
- Could store rotation field in the task table, as before, but that is
particularly inelegant.
- Could make Blob and/or Field objects image-aware, and have them store
rotation as an extra field in the blob table.
- Also allows the potential to preserve more source information, e.g. EXIF,
because no image manipulations are stored.
- ... for example:
.. code-block:: cpp
new integer field: blob.image_rotation_deg_ccw
new text field: blob.filetype // e.g. "png"
QImage Blob::image() const; // and cache it
void Blob::rotateImage(int angle);
void Blob::setImage(const QImage& image);
QImage FieldRef::image() const;
void FieldRef::rotateImage(int angle);
- Store only final rotated images and do the rotation in the background.
- I tried the Blob method (with rotation as a field in the Blob table) --
massively faster than before. Makes the difference between dire and
respectable performance.
Why not code it all in Java?
----------------------------
- The default Java UI is Swing:
https://www.reddit.com/r/java/comments/383e2c/whats_the_actual_modern_way_to_make_a_gui_with/
- Swing is not portable to iOS:
http://creamtec.com/products/ajaxswing/solutions/java_swing_ui_on_ipad.html
- JavaFX is another GUI standard, which is newer. It's not supported on all
operating systems (though it does support iOS):
http://stackoverflow.com/questions/20860931/is-it-possible-to-run-javafx-applications-on-ios-android-or-windows-phone-8
https://www.youtube.com/watch?v=a3dAteWr40k&feature=youtu.be
- SQLite would be via JDBC or similar
http://stackoverflow.com/questions/41233/java-and-sqlite
- Also, http://tech.jonathangardner.net/wiki/Why_Java_Sucks;
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
===============================================================================
.. rubric:: Footnotes
.. [#sqlcipher] See https://www.zetetic.net/sqlcipher/design/