Skip to content
master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 

Rally-Sport Content

A backend app with a frontend view to host and deliver user-made content for Rally-Sport/RallySportED.

The app can be found live on the web here.

A screenshot of Rally-Sport content

What's this about?

Rally-Sport Content provides modders of Rally-Sport (the mid-90s racing game) a centralized service to share with others the content they've made.

Rally-Sport Content is aimed at content made using the RallySportED toolset; and integrates with browser-based implementations of those tools. For example, you can directly open tracks hosted on Rally-Sport Content in the browser-based RallySportED track editor.

Communicating with the API

Rally-Sport Content provides the end-user a REST API to access hosted content.

The API supports the following requests: GET, POST, and DELETE; although some content only supports a subset of these.

GET

Information (including raw data) about resources can be queried via GET requests.

URL Output
/rallysport-content/[resource]/ Resource listing as a HTML page.
/rallysport-content/[resource]/?metadata=1 Resource metadata in JSON format.
/rallysport-content/[resource]/?json=1&id=[resource-id] The given resource's data in JSON format.*
/rallysport-content/[resource]/?zip=1&id=[resource-id] The given resource's data in a ZIP archive.*

*Supported for track resources only.

Examples

Request: GET /rallysport-content/tracks/

Response:

<!doctype html>
<html>
    ...
</html>

Request: GET /rallysport-content/tracks/?metadata=1

Response:

[
    {
        "name": "TrackA",
        "id": "track.xxx-xxx-xxx",
        "creatorID": "user.xxx-xxx-xxx",
        "width": 64,
        "height": 64
    },
    {
        "name": "TrackB",
        "id": "track.xxx-xxx-xxx",
        "creatorID": "user.xxx-xxx-xxx",
        "width": 128,
        "height": 128
    }
]

Request: GET /rallysport-content/tracks/?json=1&id=track.xxx-xxx-xxx

Response:

[
    {
        "container": "...",
        "manifesto": "...",
        "meta":
        {
            "internalName": "TrackA",
            "displayName": "TrackA",
            "width": 64,
            "height": 64,
            "id": "track.xxx-xxx-xxx",
            "creatorID": "user.xxx-xxx-xxx"
        }
    }
]

Request: GET /rallysport-content/tracks/?zip=1&id=track.xxx-xxx-xxx

Response:

"PK..."

POST

New resources can be added via POST requests.

URL Body
/rallysport-content/[resource]/ multipart/form-data*

*Must also include a PHPSESSID cookie that identifies the requester as a logged-in user.

Instead of directly issuing POST requests, please use the HTML form provided for the particular resource at /[resource]/?form=add.

DELETE

Existing resources can be removed via DELETE requests.

URL Body
/rallysport-content/[resource]/?id=[resource-id] (none)*

*Supported for track resources only. Must also include a PHPSESSID cookie that identifies the requester as a logged-in user.

Instead of directly issuing DELETE requests, please use the HTML form provided for the particular resource at /[resource]/?form=delete.

Hosting the service

Heroku with PostgreSQL

The Rally-Sport Content repo comes pre-configured for pushing to Heroku as a PHP node with a PostgreSQL database.*

Follow Heroku's deployment instructions at https://devcenter.heroku.com/articles/getting-started-with-php.

* Warning: The app is currently undergoing restructuring in its database component, due to which the master branch should be considered experimental and not ready for production. Most notably, the PostgreSQL implementation at this time uses a placeholder pepper value for hashing user email addresses, making any database created by this implementation incompatible with the eventual non-placeholder implementation. Commit 7a199a is about the last one prior to this compatibility-breaking work, but that version doesn't support Heroku or PostgreSQL.

PHP server with MySQL

To host Rally-Sport Content on a PHP 7.1-compatible, MySQL-enabled* server, do the following:

  1. Set up your database tables as per the Database subsection.
  2. Update the email addresses in api/emailer.php; and ensure your server is configured for PHP's mail function.
  3. Copy the rallysport-content/ directory onto your server.
    • The server's client-facing directory structure should be <host>/rallysport-content/ - e.g. tarpeeksihyvaesoft.com/rallysport-content/ - as some of Rally-Sport Content's code makes a hard-coded assumption of such.
  4. Also host the browser-based RallySportED editor, at <host>/rallysported/ - e.g. tarpeeksihyvaesoft.com/rallysported/.

* The app is currently undergoing restructuring to become database system agnostic, due to which MySQL is temporarily not supported by the master branch. Commit 7a199a is about the last one prior to this compatibility-breaking work.

Database

Rally-Sport Content uses one database table per resource type.

The following samples show how to create the tables in PostgreSQL.

Resource: Users

CREATE TABLE rsc_users (
    id SERIAL PRIMARY KEY,
    resource_id VARCHAR(64) UNIQUE NOT NULL,
    resource_visibility SMALLINT NOT NULL,
    resource_data_hash_sha256 VARCHAR(64) UNIQUE NOT NULL,
    creation_timestamp BIGINT NOT NULL,
    password_hash_php VARCHAR(255) UNIQUE NOT NULL,
    email_hash_sha256 VARCHAR(64) UNIQUE NOT NULL,
    password_reset_token VARCHAR(64) DEFAULT NULL,
    password_reset_token_expires BIGINT DEFAULT NULL,
    php_session_id VARCHAR(64) DEFAULT NULL
);

Description of columns

Column Description
password_hash_php A one-way salted hash of the user's password, obtained from PHP's password_hash function.
email_hash_sha256 A one-way peppered SHA256 hash of the user's email address.
password_reset_token A random string of characters, (re-)generated when the user requests a password reset. Used as a one-time authorization token when resetting the password.
password_reset_token_expires A Unix epoch timestamp marking the time after which password_reset_token becomes invalid.
php_session_id The PHPSESSID string of the most recent session that logged into this user's account. Will be reset to NULL when the user logs out, and used to enforce a limit of one active session per account.
Continues here

Resource: Tracks

CREATE TABLE rsc_tracks (
    id SERIAL PRIMARY KEY,
    resource_id VARCHAR(64) UNIQUE NOT NULL,
    resource_visibility SMALLINT NOT NULL,
    resource_data_hash_sha256 VARCHAR(64) UNIQUE,
    creator_resource_id VARCHAR(64) NOT NULL,
    creation_timestamp BIGINT NOT NULL,
    download_count INT DEFAULT 0,
    track_name VARCHAR(8) UNIQUE,
    track_width SMALLINT,
    track_height SMALLINT,
    track_container_gzip TEXT,
    track_manifesto_gzip TEXT,
    kierros_svg_gzip TEXT
);

Description of columns

Column Description
download_count A value expressing how many times this track's data has been requested from the database. Only counts requests for data, not metadata.
track_container_gzip A GZIPped, Base64-encoded string of the data of the track's container file.
track_manifesto_gzip A GZIPped, Base64-encoded string of the track's manifesto file.
kierros_svg_gzip A GZIPped, Base64-encoded string representing an SVG image of the track's KIERROS data (the CPU driver's path around the track).
Continues here

Common columns

The following columns are common to all resource tables.

Column Description
resource_id A string corresponding to the resource type's ResourceID (cf. resource-id.php).
creator_resource_id A string corresponding to the UserResourceID (cf. resource-id.php) of the user who uploaded this resource.
resource_visibility A value corresponding to ResourceVisibility (cf. resource-visibility.php).
resource_data_hash_sha256 A SHA256 hash of the resource's pertinent data. Used e.g. to detect duplicates of the resource.
creation_timestamp A Unix epoch timestamp of when this resource was added to the database.

Administrating

Backing up content

All user-submitted content is stored in the database, so backing up the database is sufficient to back up content data.

Navigating the codebase

API entry points can be found in the various index.php files - e.g. tracks/index.php handles requests arriving to /tracks/.

The entry points direct incoming requests to relevant functions in the codebase.

Requests will always be responded to via a Response object (cf. api/response.php). For example, exit(Response::code(404)->error_message("Oops")) will respond to the client with code 404 and the error message "Oops".

License

Rally-Sport Content is licensed under GPL2-or-later, with the exception of api/common-scripts/zip-file.php (see that file for details).

Distributions of Rally-Sport Content that include the aforementioned zip-file.php should be made under GPL2-only.

Authors and credits

Rally-Sport Content is developed by Tarpeeksi Hyvae Soft.

The HTML view in Rally-Sport Content makes use of icons provided by Font Awesome.