Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: build and test
on:
push:
branches:
- main
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- name: get code
uses: actions/checkout@v4
- name: Setup Bazel environment
uses: bazel-contrib/setup-bazel@0.15.0
with:
bazelisk-cache: true
disk-cache: ${{ github.workflow }}
repository-cache: true
- name: setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: build docker image
run: docker build -f Dockerfile -t cpp-analytics-devops:v1 .
- name: run docker container tests (docker image run in the background)
run: |
docker run -d -p 8080:8080 cpp-analytics-devops:v1
sleep 5
curl --fail --show-error --silent "http://127.0.0.1:8080/factorize?number=1000" || echo "API request failed."
sleep 5
curl --fail --show-error --silent "http://127.0.0.1:8080/simulate/pi?iterations=1000000" || echo "API request failed."
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# run this file with: docker build -f Dockerfile -t rest-api-container:v1 .
# build
FROM ubuntu:22.04 as builder
RUN apt-get update && apt-get install -y curl gnupg apt-transport-https g++ clang
RUN apt-get update && apt-get install -y curl unzip \
&& ARCH=$(uname -m | sed 's/aarch64/arm64/') \
&& echo "Detected architecture: $ARCH" \
&& curl -fsSL https://releases.bazel.build/8.4.2/release/bazel-8.4.2-linux-$ARCH \
-o /usr/local/bin/bazel \
&& chmod +x /usr/local/bin/bazel
WORKDIR /app
COPY . .
RUN bazel build //src:mainProg

# runtime
FROM ubuntu:22.04
WORKDIR /app
COPY --from=builder /app/bazel-bin/src/mainProg /app/server
RUN chmod +x /app/server
EXPOSE 8080
CMD ["./server"]
7 changes: 7 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module(
name = "cpp-analytics-docker",
version = "1.0.0",
)

bazel_dep(name = "googletest", version = "1.17.0")
bazel_dep(name = "cpp-httplib", version = "0.22.0")
141 changes: 140 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,141 @@
# cpp-analytics-devops
Project demonstrating C++ algorithms (factorization, Monte Carlo π) with Bazel builds, Docker images, Kubernetes deployment, autoscaling, monitoring, and CI/CD pipelines

A modern **C++ microservice project** demonstrating mathematical analytics, and DevOps practices. This project exposes a lightweight REST API for computational mathematics (prime factorization and Monte Carlo π estimation) and showcases full integration with **Bazel**, **Docker**, **Kubernetes**, and **GitHub Actions**.

---

## 🚀 Features

### 🧮 Math & Analytics API

* **Prime Factorization** using Pollard’s Rho and Miller–Rabin primality test.
* **Monte Carlo Simulation** for estimating the value of π.
* Implemented fully in **C++17**, designed for high performance and modularity.

### 🌐 RESTful API

* Built with [`cpp-httplib`](https://github.com/yhirose/cpp-httplib) (header-only HTTP/HTTPS library).
* Exposes endpoints:

* `GET /factorize?number=<int>` → returns factors of the input number.
* `GET /simulate/pi?iterations=<int>` → estimates π via Monte Carlo.

### 🏗️ Modern Build System

* **Bazel** is used for building, testing, and dependency management.
* Reproducible, cross-platform builds compatible with macOS and Ubuntu.

### 🐳 Containerization

* Multi-stage **Dockerfile**:

* **Builder stage:** compiles with Bazel.
* **Runtime stage:** runs the compiled binary only (minimal footprint).
* Example build and run:

```bash
docker build -t cpp-analytics-devops .
docker run -p 8080:8080 cpp-analytics-devops
```

### ⚙️ CI/CD Integration

* **GitHub Actions** automates:

* Build and test pipelines.
* Docker image creation and publishing.
* Optional K8s deployment hooks.

---

## 🔧 Endpoints Summary

| Method | Endpoint | Description |
| ------ | ------------------------------- | ----------------------------------------- |
| GET | `/factorize?number=<int>` | Factorizes the given number. |
| GET | `/simulate/pi?iterations=<int>` | Estimates π using Monte Carlo simulation. |

Example usage:

```bash
curl "http://localhost:8080/factorize?number=1024"
curl "http://localhost:8080/simulate/pi?iterations=1000000"
```

---

## 🧱 Project Structure

```
cpp-analytics-devops/
├── BUILD # Root Bazel build file
├── MODULE.bazel # Bazel module configuration
├── src/ # Core source code
│ ├── api/ # REST server implementation
│ ├── factor.cpp/.h # Pollard's Rho + Miller–Rabin
│ ├── montecarlo.cpp/.h # Monte Carlo π estimator
│ └── main.cpp # Entry point
├── tests/ # Unit tests
├── docker/ # Dockerfile and related assets
├── k8s/ # Kubernetes manifests
├── docs/ # Documentation
└── .github/workflows/ # CI/CD pipelines
```

---

## ⚡ Quick Start

### 1️⃣ Build Locally

```bash
bazel build //src:mainProg
```

### 2️⃣ Run Locally

```bash
bazel run //src:mainProg
```

Server starts on `http://0.0.0.0:8080`.

### 3️⃣ Docker

```bash
docker build -t cpp-analytics-devops .
docker run -p 8080:8080 cpp-analytics-devops
```

---

## 🧩 Tech Stack

| Category | Tool |
| ----------------------------- | ------------------------------ |
| Language | C++17 |
| Build System | Bazel |
| Web Framework | cpp-httplib |
| CI/CD | GitHub Actions |
| Containerization | Docker |
| Orchestration(future work) | Kubernetes |
| DB (future work) | PostgreSQL integration planned |

---

## 🧠 Future Work

* Add Kubernetes for orchestration
* Integrate PostgreSQL for result persistence.
* Add caching layer for factorization results.

---

## 📄 License

Licensed under the [MIT License](./LICENSE).

---

**Author:** RaphaelRevivor
**Repository:** [cpp-analytics-devops](https://github.com/RaphaelRevivor/cpp-analytics-devops)
Empty file removed docker/Dockerfile
Empty file.
7 changes: 7 additions & 0 deletions src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ cc_library(
hdrs = [
"factor.h"
],
visibility = [
"//:__subpackages__",
],
)

cc_library(
Expand All @@ -16,6 +19,9 @@ cc_library(
hdrs = [
"montecarlo.h"
],
visibility = [
"//:__subpackages__",
],
)

cc_binary(
Expand All @@ -27,5 +33,6 @@ cc_binary(
deps = [
":factorLib",
":montecarloLib",
"//src/api:restapiLib",
],
)
17 changes: 17 additions & 0 deletions src/api/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cc_library(
name = "restapiLib",
srcs = [
"rest.cpp"
],
hdrs = [
"rest.h",
],
deps = [
"@cpp-httplib//:httplib",
"//src:montecarloLib",
"//src:factorLib",
],
visibility = [
"//:__subpackages__",
],
)
36 changes: 36 additions & 0 deletions src/api/rest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "rest.h"

int RestApi::runServer()
{
svr.Get("/factorize", [&] (const Request& req, Response& res) {
auto nStr = req.get_param_value("number");
int64_t n = stoll(nStr);
auto factorization = Factorization(n);
auto factorsStr = factorization.getAllFactorsInString();

// cout << "Server is trying to reply: " << factorsStr << endl;

res.status = 200;
res.set_content(factorsStr, "text/plain");
});

svr.Get("/simulate/pi", [&] (const Request& req, Response& res) {
auto nStr = req.get_param_value("iterations");
int64_t n = stoll(nStr);
auto montecarloPi = MonteCarloPi(n);
auto piStr = to_string(montecarloPi.estimatePi());

// cout << "Server is trying to reply: " << piStr << endl;

res.status = 200;
res.set_content(piStr, "text/plain");
});

if (!svr.listen("0.0.0.0", 8080)) {
std::cerr << "Error starting server\n";
return 1;
}
}



28 changes: 28 additions & 0 deletions src/api/rest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef REST_H
#define REST_H

// #define CPPHTTPLIB_OPENSSL_SUPPORT

#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <httplib.h>

#include "src/factor.h"
#include "src/montecarlo.h"

using namespace httplib;

class RestApi
{
public:
RestApi() = default;
~RestApi() = default;
int runServer();

private:
Server svr;
};

#endif
29 changes: 28 additions & 1 deletion src/factor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ Factorization::Factorization(int64_t n) : n(n)
srand(time(0));
}

string Factorization::getAllFactorsInString()
{
string output = "";
auto factors = getAllFactors();
for(auto iter = factors.begin(); iter != factors.end(); iter++)
{
output += to_string(*iter);
if (iter != prev(factors.end()))
output += ",";
}
output += "\n";
return output;
}

vector<int64_t> Factorization::getAllFactors()
{
vector<int64_t> output = {};
Expand Down Expand Up @@ -92,7 +106,11 @@ int64_t Factorization::selectX0(const int64_t& input)
/// @return f(x)
int64_t Factorization::squareMod(const int64_t& x, const int64_t& c, const int64_t& input)
{
#ifdef _MSC_VER
int64_t output = (x * x + c) % input;
#else
__int128_t output = (x * x + c) % input;
#endif
return output;
}

Expand Down Expand Up @@ -147,9 +165,13 @@ bool Factorization::millerRabin(const int64_t& input)
if (base >= input)
continue;

// calculate x = a^d % n
#ifdef _MSC_VER
int64_t x = mod_pow(base, d, input);
#else
__int128_t x = mod_pow(base, d, input);
#endif

// calculate x = a^d % n
if (x == 1 || x == input - 1)
continue;

Expand All @@ -175,7 +197,12 @@ bool Factorization::millerRabin(const int64_t& input)
/// @return mod power result
int64_t Factorization::mod_pow(const int64_t& b, const int64_t& d, const int64_t& input)
{

#ifdef _MSC_VER
int64_t result = 1;
#else
__int128_t result = 1;
#endif
int64_t base = b;
int64_t dd = d;
base = base % input;
Expand Down
2 changes: 2 additions & 0 deletions src/factor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cmath>
#include <cstdlib>
#include <numeric>
#include <string>

using namespace std;

Expand All @@ -17,6 +18,7 @@ class Factorization
Factorization(int64_t n);
~Factorization() = default;
vector<int64_t> getAllFactors();
string getAllFactorsInString();
int64_t getFactor(const int64_t& input);

private:
Expand Down
Loading
Loading