Skip to content

Architecture

Flynn, Conor edited this page Dec 7, 2022 · 6 revisions

Introduction

This section covers the general overview of the DeFi-Data-Engine's architecture including but not limited to:

  • General system overview
  • Internal routing architecture explanation
  • Routing architecture current implementation
  • Implemented processes overview
  • Implemented processes subroutines
  • Data transfer system
  • System time series analysis
  • REST API overview
  • REST API connection architecture

General System Overview

The DeFi-Data-Engine (DFDE) is a native Java application designed to support the transferring, processing, and storage of high frequency data streams. To accomplish this, the system has been designed with multiple considerations such as: expansion into other sources, multi-user threading capabilities, and language agnostic understanding.

There are three main component types to the DFDE: the Java Applications, the External (R) Applications, and the External Data Sources. The Java Applications are the two primary applications consisting of the main engine architecture and the REST API. The External Applications are any external programs that utilize the engine to extract data. Finally External Data Sources are implemented sources from which the engine can extract data and parse it into the DFDE ecosystem. Below is a high level overview of the DFDE and all of the primary components that interact with the engine. image

The primary focus of this section will be on the "Engine Processes" component which houses all major internal communication within the engine. This will be further expanded upon in later sections, breaking down the individual processes, how they are implemented, and how they can be expanded upon. Also note that R is not the only supported language, however it is the primary language utilized by the lab and therefore will be the most heavily documented. Please note that any language that supports Socket connections and REST API calls can utilize the DFDE.

Internal Routing Architecture

Routers

Introduction

To mediate and standardize all communication across different processes within the engine, a process similar to a network has been implemented (hence the use of "routers" and "packets"). All routers are connected through a "manager" which stores and groups all routers into a single object which allows for communication between all of them. Each router has a unique id (uuid) and a tag which are used to identify it. For example, the Core process has the uuid core and the tag 'COR'. Each tag is denoted by a three character string (although not required it is standard practice to save memory).

Framework

The abstract Router class is listed in the org.framework.router package and holds the framework for implementing a new process. Below are all core methods and their descriptions used within the class. Please note all methods not listed with abstract are implemented and just not shown in this example.

// base constructor
public Router(String uuid, String tag) {}

// constructor for auto-connecting the Router to an existing Manager
public Router(String uuid, String tag, Manager manager) {}

// returns uuid of the Router
public final String getUUID() {}

// returns tag of the Router
public final String getTag() {}

// returns the Manager the Router is connected to
public final Manager getManager() {}

// connects the Router to a new Manager
public final void setManager(Manager manager) {}

// connects list of Routers to this Router
public final void connect(Router... routers) {}

// checks to see if a Router with the given tag is connected to this Router
public final boolean isConnected(String tag) {}

// checks to see if a Router is connected to this Router
public final boolean isConnected(Router router) {}

// returns all connected Routers to this Router
public final Collection<String> connectedTags() {}

// sends a Packet with the given data to a connected Router
// returns a Response object
public final Response send(String tag, String sub_tag, HashMap<String, String> data) {}

// sends a Packet with the given data to a connected Router
// returns a Response object
// note all data is in the format ["key_1", "value_1", "key_2", "value_2",..., "key_n", "value_n"]
public final Response send(String tag, String sub_tag, String... data) {}

// function that receives an incoming Packet
public final Response receive(Packet packet) {}

// function for adding a sub-process to the Router
public final void addProcess(String subtag, Method method) {}

// function used for handling incoming processes
// users do NOT need to interact with this function
private final Response process(Packet packet) {}

// function which auto adds any function labeled "process----"
// to the Router which can then be accessed
// for example the function "processSUBS" will be added to the function
// under the sub_tag "SUBS" that can be called from other Routers
private final void defineProcesses() throws NoSuchMethodException, SecurityException {}

Examples

Definitions

We define the two Router objects.

public class Router1 extends Router {
  public Router1() {
    super("router1", "RT1");
  }
}

public class Router2 extends Router {
  public Router2() {
    super("router2", "RT2");
  }

  public Response processEXPL(Packet packet) {
    System.out.println(packet.getData("sample"));
    return ResponseFactory.response200();
  }
}

Connecting the Routers

Router1 rt1 = new Router1();
Router2 rt2 = new Router2();
  
rt1.connect(rt2);
rt1.isConnected("RT2"); // true
}

Sending a Packet

// this call will print the data stored under "sample"
// and then return a 200 response
rt1.send("RT2", "EXPL", "sample", "this-is-printed").code(); // 200

Packets

Introduction

Each process has sub-processes as well denoted by four character strings. These sub-processes carry out actions within the engine and are the standard way processes communicate with one another.