FrIC (FII-STAW 2019)

Authors
Apostu Razvan @razgraf & Badarau Bogdan
Public repository
Github

Introduction

The main scope of the FRIC project is to build and deploy a library for fractal generation. Our final product will be delivered with 2 large components, meant for public use:

  1. The library
  2. The platform

Structure

We can break down the structure of the project into:

The library

A javascript module that can be implemented and used to generate fractals based on user provided definitions. The module will also expose some functionality regarding the user system, the token related quota and more info regarding the AWS server-side implementation.

The platform

A front facing platform with 2 main responsibilities:

  1. Generating tokens that will be used to access the server functionality, based on a given user quota.
  2. Generating fractals through the offical UI builder. This front facing part of the platform will provide the user with a UI for generating fractals (without the need of explicit coding) and a method of exporing other user submitted fractals.

Implementation

Following the official Requirements we are going to build the final product(s) in a stack comprised of

Library

The library is going to be exposed to the programmer through a simple ES6 module (hosted maybe on NPM) that will structure all the functionality (Reference: ModularJS).

Another approach would be to use ES6 modules and transpile them using babel for ES5 support, but we will take this into consideration at a later date, based on the progress we make.

Global types

For the sake of simplicity, we are going to use JSDOC typedef to declare some objects and variables. These will be widely used throught our documentation.

  • Auth

    
    
                    /**
                    * @typedef {Object} Auth
                    * @property {string} id - The unique user identification string 
                    * @property {token} token - The value which will determine the quota of a user
                    */
      
                    

    A user can own more than one token, based on the priviledges he chooses for it.

  • Identity

    
                      /**
                      * @typedef {Object} Identity
                      * @property {string} name - The unique user identification string 
                      * @property {Object[]} history - A brief history of the recent usage of the token
                      * @property {string} history[].timestamp - Time of creation for history item
                      * @property {string} history[].action - Type of history item
                      * @property {string} history[].payload - Extra data that can describe the action
                      * @property {Object} quota - The remaining usage quota for that particular token
                      * @property {string} quota.quantity - Remaining horse power
                      * @property {string} quota.refresh - Timestamp for next quota refresh (if any)
                      */
                      

    We will define the remainig quota based on either computation seconds or access count. Will decide this when we have a better understanding of AWS pricing.

  • Fractal

    
                          /**
                          * @typedef {Object} Fractal
                          * @property {string} id - A unique identifier for the generated fractal
                          * @property {string} url - The link for a .png image descibing the generated fractal
                          * @property {Object} data - Extra data about the fractal (including but not limited to its ordered rules, its length and definition etc.)
                          */
                          

    Reference: HTTPStatus, @type {Fractal}

  • Definition

    
                            /**
                            * @typedef {Object} Definition - Parameters that will describe rules and attributes for the soon-to-be generated @type {Fractal}
                            * @property {string} type - One of ["LSystem"]
                            * [ if type === "LSystem" ]
                            *     @property {number} iterations - e.g. 3
                            *     @property {string} start - e.g. "X"
                            *     @property {Array<Object>} rules - e.g. [{left : "X", right : "X+YF+"}]
                            *     @property {int} x - start point on X axis e.g. 100
                            *     @property {int} y - start point on Y axis e.g. 100
                            *     @property {number} lineSize
                            *     @property {number} angle - e.g. 360
                            */
                            
  • Response

    
                        /**
                        * @typedef {Object} Response
                        * @property {string} status - A HTTP response status code of the query
                        * @property {string} message - A contextual response message from the server e.g. "Succes" vs "Access not granted"
                        * @property {Fractal} fractal - If everything goes smooth, it will contain the fractal definition
                        */
                        

    Reference: HTTPStatus, @type {Fractal}

Exposed methods

Because our library will rely on heavy communication with the server, we are going to design most of the calls as "Promises". This way, we can allow for an intuitive and controlled async experience.

  1. FractalBuilder.init(...params)
  2. FractalBuilder.who()
  3. FractalBuilder.build(...params)
FractalBuilder.init(...params)

To instantiate the module, after import a user will have to initialize it, either through the init() method.


                    /**
                     * Initializes the environment
                     * @param {Auth} auth
                    */
                    FractalBuilder.init(auth)
                    

Each time the programmer is going to make use of our library, the id and token will be checked for validity and available quota.

This authenthication object will be sent inside a header parameter and wrapped in the shape of a JWT. This will allow us to verify if the request has been tempered with through the JWT signature feature.

FractalBuilder.who()

In order to check his/her identity based on the Auth object data, a user can use the .who() method. The promise will return an object describing the user's identity (@type {Identity}).

              
                  /**
                   * Returns user identity based on the auth object
                   * @returns {Promise.<Identity|Error>} - If the auth object is not defined yet, we'll throw an Error describing this issue
                  */

                  FractalBuilder.who(auth)
                  .then(identity => {...})
                  .catch(error => {...})
                  
FractalBuilder.build(...params)

Building a fractal will be done through the build function. This will return a response (@type {Response}) containing some flags and (if successful) the @type {Fractal} object, descibing the created shape.

              
                /**
                 * Returns user identity based on the auth object
                 * @returns {Promise.<Response|Error>} - If the auth object is not defined yet, we'll throw an Error describing this issue
                */

                FractalBuilder.who(auth)
                .then(response => {...})
                .catch(error => {...})
                

Server & Computations

Our AWS Lambda functions will handle generating the fractals.

How will it work?

Our library will mainly be made up of requests. The build() functionality will send us (among other stuff) a Definition of the Fractal required by the user. If this is a valid request (user is authorized and definition is valid), we'll rely on a AWS Lambda function to compute the shape of the fractal, create an image and drop it into our S3. Additional data will be stored in a NoSQL DynamoDB instance.

The language used to design these functions will be Node JS.

How do we validate and authorize?

In order to use the library, a user must first request a token. Refernce: 3.4.1 Features - Stage A

Platform

Our Platform will run in a static context and it will be hosted with AWS S3. It will also access Lambda Functions which will act as an API for our platform. We'll design it as a mixture of SPA and MPA (hybrid, but with more focus on the SPA aspect). Everything will be kept as modular as possbile by employing a "synthetic React" approach (every element will be wrapped in a pseudo-component that we'll use to manage it when needed).

API

For a preview of the beta version of our API, we used Swagger to map some of the endpoints and functionality we'll use both internally (for the plaform Stage A and B) and externally/publicly (inside our library).

Swagger Preview

Features

All the following features will be linked to AWS Lamda functions.

  1. Stage A: User/Token manager

    The primary source of token generation for new users will be our Token Manager Platform. The sole purpose of this webpage will be to generate a user ID - Token pair, that will later be provided at each use of the library. (Similar to the Google API KEY system). We chose to use an ID - Token pair rather than a simple Token because of the later possibility to scale and use the same system for user accounts (Stage B of the Platform).

    Rough actions:

    • create user
    • remove user
    • create token for user with given quota
    • remove token for user
    • extend quota for token of user
    • constrain quota for token of user
    • get user with tokens with quota
    • is user - token pair valid
    • is user - token (quota) available
  2. Stage B: Fractal explorer and builder

    Pages

    • Fractal Builder (editor + publisher)
    • Fractal Explorer
    • Fractal Leaderboard (voting system for best looking fractals)

    Requests

    • retrieve fractal image
    • retrieve fractal definition
    • retrieve user fractals
    • retrieve leaderboard fractals
    • retrieve latest fractals
    • ...

Database

We'll use the AWS DynamoDB service to structure our database.

Structure

Database
Partial database structure for a NoSQL implementation (View file)