Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
35 changes: 35 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml for multi-platform support
name: Build with CMake
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
env:
# CMake build type
BUILD_TYPE: Release

jobs:
install-dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
# No point installing protobuf - the version on apt is too old
sudo apt-get install -y libceres-dev
sudo apt-get install -y libpistache-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/backend/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${{github.workspace}}/backend

- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/backend/build --config ${{env.BUILD_TYPE}}

- name: Test
working-directory: ${{github.workspace}}/backend/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}
13 changes: 0 additions & 13 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
# Cmake artifacts
build

# Clangd artifacts
.clangd
compile_commands.json
.cache

# Compilation artifacts
*.o
a.out
solver

# Other
.vscode
.DS_Store
1 change: 1 addition & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
3 changes: 3 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build
.cache
compile_commands.json
20 changes: 20 additions & 0 deletions backend/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.16)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # For clangd support
set(CIRCUITSOLVER_BUILD_TESTS OFF)
set(BUILD_SHARED_LIBS
OFF
CACHE BOOL "Build all libraries as static" FORCE)

project(circuitSolverApp)
find_package(PkgConfig)
pkg_check_modules(Pistache REQUIRED IMPORTED_TARGET libpistache)

# build dir is relative to the build dir of this target
add_subdirectory(../native_lib ../../native_lib/build)
add_executable(circuit-solver src/main.cpp src/circuitSolverService.cpp
src/circuitSolverService.h)
target_link_libraries(circuit-solver PRIVATE circuitSolverLib
PkgConfig::Pistache)
26 changes: 26 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM ubuntu:20.04

RUN \
apt-get update && \
# CMake
apt-get install -y cmake && \
# google-glog + gflags
apt-get install -y libgoogle-glog-dev libgflags-dev && \
# Use ATLAS for BLAS & LAPACK
apt-get install -y libatlas-base-dev && \
# Eigen3
apt-get install -y libeigen3-dev && \
# SuiteSparse (optional)
apt-get install -y libsuitesparse-dev && \
# git
apt-get install -y git && \
apt-get install -y curl unzip &&\
apt-get install -y g++
RUN mkdir circuitSolver
COPY . /circuitSolver
WORKDIR /circuitSolver

RUN \
cmake . &&\
mkdir build && cd build && \
cmake --build ..
29 changes: 29 additions & 0 deletions backend/example_request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"edges": {
"186c9b6f-d4b8-479c-92b8-b8e79e559785": {
"id": "186c9b6f-d4b8-479c-92b8-b8e79e559785",
"from_id": "bc48a7b8-5f3e-4cdd-9b38-348351fbfaf0",
"to_id": "c4ac9c35-570c-41a3-a507-84873acd69a6",
"resistor": {
"resistance": 2.0
}
},
"24c47fea-3c60-40c4-a3bb-cc239d8d7f93": {
"id": "24c47fea-3c60-40c4-a3bb-cc239d8d7f93",
"from_id": "bc48a7b8-5f3e-4cdd-9b38-348351fbfaf0",
"to_id": "c4ac9c35-570c-41a3-a507-84873acd69a6",
"voltage_source": {
"voltage": 5.0
}
}
},
"vertices": {
"c4ac9c35-570c-41a3-a507-84873acd69a6": {
"id": "c4ac9c35-570c-41a3-a507-84873acd69a6"
},
"bc48a7b8-5f3e-4cdd-9b38-348351fbfaf0": {
"id": "bc48a7b8-5f3e-4cdd-9b38-348351fbfaf0",
"voltage": 0.0
}
}
}
63 changes: 63 additions & 0 deletions backend/src/circuitSolverService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "circuitSolverService.h"
#include <circuit_solver/api.h>
#include <stdexcept>

void CircuitSolverService::configureRoutes() {
Pistache::Rest::Routes::Post(
router, "/solve",
Pistache::Rest::Routes::bind(&CircuitSolverService::solveProtobuf, this));
Pistache::Rest::Routes::Post(
router, "/solve/json",
Pistache::Rest::Routes::bind(&CircuitSolverService::solveJson, this));
}

void CircuitSolverService::solveProtobuf(const Request &request,
Response response) {
try {
const std::string body = request.body();
std::string output = solveGraphFromString(body);
response.send(Pistache::Http::Code::Ok, output,
// Pistache doesn't support application/protobuf as a MIME
// type so we set it raw
Pistache::Http::Mime::MediaType(
"application/protobuf",
Pistache::Http::Mime::MediaType::DontParse));
// TODO: figure out a good way to return a failure message
} catch (const std::runtime_error &error) {
response.send(Pistache::Http::Code::Not_Found, error.what(),
MIME(Text, Plain));
} catch (const std::logic_error &error) {
response.send(Pistache::Http::Code::Not_Found, error.what(),
MIME(Text, Plain));
} catch (...) {
response.send(Pistache::Http::Code::Internal_Server_Error, "Internal error",
MIME(Text, Plain));
}
}

void CircuitSolverService::solveJson(const Request &request,
Response response) {
try {
const std::string body = request.body();
std::string output = solveGraphFromJson(body);
response.send(Pistache::Http::Code::Ok, output, MIME(Application, Json));
} catch (const std::runtime_error &error) {
response.send(Pistache::Http::Code::Not_Found, error.what(),
MIME(Text, Plain));
} catch (const std::logic_error &error) {
response.send(Pistache::Http::Code::Not_Found, error.what(),
MIME(Text, Plain));
} catch (...) {
response.send(Pistache::Http::Code::Internal_Server_Error, "Internal error",
MIME(Text, Plain));
}
}

void CircuitSolverService::run() {
std::cout << "Starting on port " << port << " with " << numThreads
<< " threads.\n";
endpoint->init(Pistache::Http::Endpoint::options().threads(numThreads));
configureRoutes();
endpoint->setHandler(router.handler());
endpoint->serve();
}
30 changes: 30 additions & 0 deletions backend/src/circuitSolverService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <pistache/endpoint.h>
#include <pistache/router.h>
#include <thread>

using Request = Pistache::Rest::Request;
using Response = Pistache::Http::ResponseWriter;
using Endpoint = Pistache::Http::Endpoint;
using Router = Pistache::Rest::Router;
class CircuitSolverService {
public:
CircuitSolverService(
unsigned port = 8000,
unsigned numThreads = std::thread::hardware_concurrency())
: port(port), numThreads(numThreads), address("localhost", port),
endpoint(std::make_shared<Pistache::Http::Endpoint>(address)) {}

void run();

private:
void configureRoutes();

void solveProtobuf(const Request &request, Response response);
void solveJson(const Request &request, Response response);

unsigned port;
unsigned numThreads;
Pistache::Address address;
std::shared_ptr<Endpoint> endpoint;
Router router;
};
14 changes: 14 additions & 0 deletions backend/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "circuitSolverService.h"
int main() {
try {
CircuitSolverService service(8000, 1);
service.run();
} catch (const std::exception &error) {
std::cerr << error.what() << '\n';
return 1;
} catch (...) {
return 1;
}

return 0;
}
31 changes: 31 additions & 0 deletions ffi_bridge/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins-dependencies
/build/
/coverage/
45 changes: 45 additions & 0 deletions ffi_bridge/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "3b62efc2a3da49882f43c372e0bc53daef7295a6"
channel: "stable"

project_type: package_ffi

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: android
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: ios
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: linux
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: macos
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: web
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
- platform: windows
create_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6
base_revision: 3b62efc2a3da49882f43c372e0bc53daef7295a6

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
3 changes: 3 additions & 0 deletions ffi_bridge/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.1

* TODO: Describe initial release.
1 change: 1 addition & 0 deletions ffi_bridge/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Add your license here.
49 changes: 49 additions & 0 deletions ffi_bridge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# ffi_bridge

A new Dart FFI package project.

## Getting Started

This project is a starting point for a Flutter
[FFI package](https://flutter.dev/to/ffi-package),
a specialized package that includes native code directly invoked with Dart FFI.

## Project structure

This template uses the following structure:

* `src`: Contains the native source code, and a CmakeFile.txt file for building
that source code into a dynamic library.

* `lib`: Contains the Dart code that defines the API of the plugin, and which
calls into the native code using `dart:ffi`.

* `bin`: Contains the `build.dart` that performs the external native builds.

## Building and bundling native code

`build.dart` does the building of native components.

Bundling is done by Flutter based on the output from `build.dart`.

## Binding to native code

To use the native code, bindings in Dart are needed.
To avoid writing these by hand, they are generated from the header file
(`src/ffi_bridge.h`) by `package:ffigen`.
Regenerate the bindings by running `dart run ffigen --config ffigen.yaml`.

## Invoking native code

Very short-running native functions can be directly invoked from any isolate.
For example, see `sum` in `lib/ffi_bridge.dart`.

Longer-running functions should be invoked on a helper isolate to avoid
dropping frames in Flutter applications.
For example, see `sumAsync` in `lib/ffi_bridge.dart`.

## Flutter help

For help getting started with Flutter, view our
[online documentation](https://docs.flutter.dev), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
4 changes: 4 additions & 0 deletions ffi_bridge/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
Loading
Loading