FONDLED THE CODE

This commit is contained in:
2025-05-06 10:36:07 -04:00
parent 9f91737781
commit c09fb31e34
8 changed files with 162 additions and 48 deletions

View File

@@ -1,28 +1,104 @@
# Traefik Redis Provider API
[Traefik](https://traefik.io/traefik/) is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. This project provides
an api manager for the [Redis provider](https://doc.traefik.io/traefik/providers/redis/) for Traefik, allowing you to use Redis as a dynamic configuration backend.
## Running the Project
### Prerequisites
- Docker
- Traefik
- Redis
### Environment Variables
- `REDIS_HOST`: The URL of the Redis server. Default is `localhost`.
- `REDIS_PORT`: The port of the Redis server. Default is `6379`.
- `REDIS_DATABASE`: The database number to use. Default is `0`.
- `HTTP_PORT`: The port to run the HTTP server on. Default is `9501`.
```shell
docker run --rm -it -p 9501:9501 scr.siteworxpro.com/traefik-api:v1.1.0
```
## Usage
### Get All Routes
```http request
GET http://localhost:9501/http/routes
Accept: application/json
```
```json
[
"route-1",
"route-2"
]
```
### Get a Route
```http request
GET http://localhost:9501/http/routes/route-1
Accept: application/json
```
```json
{
"id": "route-1",
"rule": "Host(`example.com`)",
"service": "service-1",
"middlewares": [
"middleware-1"
]
}
```
## Dev Environment
### Prerequisites
- Docker
- Docker Compose
### Starting the Runtime
```shell
export PHP_IDE_CONFIG=serverName=localhost
docker-compose up -d
```
### Start the server
```shell
docker exec -it traefik-redis-api-dev-runtime-1 rr serve
```
You can access the api at `http://localhost:9501/`
### Xdebug
xdebug needs to be built into the container before it will work
```shell
docker exec -it traefik-redis-api-dev-runtime-1 bin/xdebug.sh
```
### Install the dependencies
```shell
docker run --rm -v $(PWD):/app siteworxpro/composer install --ignore-platform-reqs
```
### Running all tests
```shell
docker run --rm -v $(PWD):/app siteworxpro/composer run tests:all
```
### migrations
create a new migration
```shell
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 create -ext sql -dir /app/db/migrations -seq create_users_table
```
## License
```text
postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable
```
Copyright (c)2025 Siteworx Professionals, LLC
```shell
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 -database "postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable" -path /app/db/migrations up
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```

View File

@@ -1,10 +1,10 @@
#volumes:
# pgdata: {}
volumes:
redisdata: {}
services:
dev-runtime:
ports:
- "8080:8080"
- "9501:9501"
volumes:
- .:/app
build:
@@ -14,24 +14,12 @@ services:
environment:
PHP_IDE_CONFIG: serverName=localhost
WORKERS: 1
HTTP_PORT: 8080
DEBUG: 1
REDIS_HOST: 192.168.1.30
REDIS_HOST: redis
# migrations:
# image: siteworxpro/migrate:v4.18.3
# restart: no
# volumes:
# - .:/app
# command: "-database 'postgres://${DB_DATABASE-siteworxpro}:${DB_PASSWORD-password}@${DB_HOST-postgres}:5432/siteworxpro?sslmode=disable' -path /app/db/migrations up"
#
# postgres:
# image: postgres:latest
# environment:
# POSTGRES_USER: ${DB_USERNAME:-siteworxpro}
# POSTGRES_PASSWORD: ${DB_PASSWORD:-password}
# POSTGRES_DB: ${DB_DATABASE:-siteworxpro}
# ports:
# - "5432:5432"
# volumes:
# - pgdata:/var/lib/postgresql/data
redis:
image: redis:latest
ports:
- "6379:6379"
volumes:
- redisdata:/data

View File

@@ -4,12 +4,28 @@ declare(strict_types=1);
namespace Siteworxpro\App\Controllers;
use Illuminate\Support\Facades\Log;
use League\Route\Http\Exception\NotFoundException;
use Nyholm\Psr7\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Siteworxpro\App\Traefik\ProtocolEnum;
abstract class Controller implements ControllerInterface
{
protected function protocolEnumFromRequest(ServerRequest $request): ProtocolEnum
{
$protocol = $request->getAttribute('protocol');
try {
return ProtocolEnum::fromString($protocol);
} catch (\InvalidArgumentException $e) {
Log::error($e->getMessage());
return ProtocolEnum::HTTP;
}
}
/**
* @param ServerRequest $request
* @return ResponseInterface

View File

@@ -20,10 +20,14 @@ class MiddlewaresController extends Controller
if ($request->getAttribute('id') !== null) {
$name = $request->getAttribute('id');
return JsonResponseFactory::createJsonResponse(RedisClient::getMiddleware($name));
return JsonResponseFactory::createJsonResponse(
RedisClient::getMiddleware($name, $this->protocolEnumFromRequest($request))
);
}
return JsonResponseFactory::createJsonResponse(RedisClient::getAllMiddlewares());
return JsonResponseFactory::createJsonResponse(
RedisClient::getAllMiddlewares($this->protocolEnumFromRequest($request))
);
}
/**
@@ -39,7 +43,7 @@ class MiddlewaresController extends Controller
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
}
RedisClient::createOrReplace($name, $data, EntityEnum::MIDDLEWARE);
RedisClient::createOrReplace($name, $data, EntityEnum::MIDDLEWARE, $this->protocolEnumFromRequest($request));
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware added successfully']);
}
@@ -55,7 +59,7 @@ class MiddlewaresController extends Controller
return JsonResponseFactory::createJsonResponse(['error' => 'Middleware is invalid'], 400);
}
RedisClient::deleteAllKeys($name, EntityEnum::MIDDLEWARE);
RedisClient::deleteAllKeys($name, EntityEnum::MIDDLEWARE , $this->protocolEnumFromRequest($request));
return JsonResponseFactory::createJsonResponse(['message' => 'Middleware deleted successfully']);
}

View File

@@ -20,10 +20,14 @@ class RoutesController extends Controller
if ($request->getAttribute('id') !== null) {
$name = $request->getAttribute('id');
return JsonResponseFactory::createJsonResponse(RedisClient::getRouter($name));
return JsonResponseFactory::createJsonResponse(
RedisClient::getRouter($name, $this->protocolEnumFromRequest($request))
);
}
return JsonResponseFactory::createJsonResponse(RedisClient::getAllRouters());
return JsonResponseFactory::createJsonResponse(
RedisClient::getAllRouters($this->protocolEnumFromRequest($request))
);
}
/**
@@ -43,7 +47,12 @@ class RoutesController extends Controller
return JsonResponseFactory::createJsonResponse(['error' => 'Rule is required'], 400);
}
RedisClient::createOrReplace($name, $data, EntityEnum::ROUTER);
RedisClient::createOrReplace(
$name,
$data,
EntityEnum::ROUTER,
$this->protocolEnumFromRequest($request)
);
return JsonResponseFactory::createJsonResponse(['message' => 'Router created successfully']);
}
@@ -55,7 +64,11 @@ class RoutesController extends Controller
{
$name = $request->getAttribute('id');
RedisClient::deleteAllKeys($name, EntityEnum::ROUTER);
RedisClient::deleteAllKeys(
$name,
EntityEnum::ROUTER,
$this->protocolEnumFromRequest($request)
);
return JsonResponseFactory::createJsonResponse(['message' => 'Router deleted successfully']);
}
@@ -70,7 +83,7 @@ class RoutesController extends Controller
$data = $request->getParsedBody();
try {
RedisClient::patchEntity($name, $data, EntityEnum::ROUTER);
RedisClient::patchEntity($name, $data, EntityEnum::ROUTER, $this->protocolEnumFromRequest($request));
} catch (\InvalidArgumentException) {
return JsonResponseFactory::createJsonResponse(['error' => 'Router not found'], 404);
}

View File

@@ -20,10 +20,14 @@ class ServicesController extends Controller
if ($request->getAttribute('id') !== null) {
$name = $request->getAttribute('id');
return JsonResponseFactory::createJsonResponse(RedisClient::getService($name));
return JsonResponseFactory::createJsonResponse(
RedisClient::getService($name, $this->protocolEnumFromRequest($request))
);
}
return JsonResponseFactory::createJsonResponse(RedisClient::getAllServices());
return JsonResponseFactory::createJsonResponse(
RedisClient::getAllServices($this->protocolEnumFromRequest($request))
);
}
/**
@@ -39,7 +43,7 @@ class ServicesController extends Controller
return JsonResponseFactory::createJsonResponse(['error' => 'loadbalancer is required'], 400);
}
RedisClient::createOrReplace($name, $data, EntityEnum::SERVICE);
RedisClient::createOrReplace($name, $data, EntityEnum::SERVICE, $this->protocolEnumFromRequest($request));
return JsonResponseFactory::createJsonResponse(['message' => 'Service updated successfully']);
}
@@ -55,7 +59,7 @@ class ServicesController extends Controller
return JsonResponseFactory::createJsonResponse(['error' => 'Service name is required'], 400);
}
RedisClient::deleteAllKeys($name, EntityEnum::SERVICE);
RedisClient::deleteAllKeys($name, EntityEnum::SERVICE, $this->protocolEnumFromRequest($request));
return JsonResponseFactory::createJsonResponse(['message' => 'Service deleted successfully']);
}

View File

@@ -120,7 +120,10 @@ class Server
*/
protected function registerRoutes(): void
{
$this->router->group('/http/routes', function (RouteGroup $router) {
$this->router->addPatternMatcher('protocolEnums', 'http|tcp|udp');
$this->router->addPatternMatcher('protocolEnumsMiddleware', 'http|tcp');
$this->router->group('/{protocol:protocolEnums}/routes', function (RouteGroup $router) {
$router->get('/', RoutesController::class . '::get');
$router->get('/{id}', RoutesController::class . '::get');
$router->post('/{id}', RoutesController::class . '::post');
@@ -128,14 +131,14 @@ class Server
$router->delete('/{id}', RoutesController::class . '::delete');
});
$this->router->group('/http/services', function (RouteGroup $router) {
$this->router->group('/{protocol:protocolEnums}/services', function (RouteGroup $router) {
$router->get('/', ServicesController::class . '::get');
$router->get('/{id}', ServicesController::class . '::get');
$router->post('/{id}', ServicesController::class . '::post');
$router->delete('/{id}', ServicesController::class . '::delete');
});
$this->router->group('/http/middlewares', function (RouteGroup $router) {
$this->router->group('/{protocol:protocolEnumsMiddleware}/middlewares', function (RouteGroup $router) {
$router->get('/', MiddlewaresController::class . '::get');
$router->get('/{id}', MiddlewaresController::class . '::get');
$router->post('/{id}', MiddlewaresController::class . '::post');

View File

@@ -18,4 +18,14 @@ enum ProtocolEnum
self::UDP => 'udp',
};
}
public static function fromString(string $value): self
{
return match ($value) {
'http' => self::HTTP,
'tcp' => self::TCP,
'udp' => self::UDP,
default => throw new \InvalidArgumentException("Invalid protocol: $value"),
};
}
}