Skip to content

Commit

Permalink
feat: create Mongo Stream Listener
Browse files Browse the repository at this point in the history
  • Loading branch information
medeirosinacio committed Jul 8, 2024
1 parent 6041e56 commit 3671a96
Show file tree
Hide file tree
Showing 17 changed files with 488 additions and 149 deletions.
9 changes: 9 additions & 0 deletions .docker/mongo/create-new-record.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

mongosh "mongodb://mongo/default?replicaSet=rs0&readPreference=primary" <<EOF
db.records.insertOne({
transaction_id: "txn12345",
user_id: "1",
expires_at: new Date(Date.now() + 60 * 1000) // Define a expiração para 1 minuto a partir de agora
});
EOF
58 changes: 2 additions & 56 deletions .docker/mongo/reset.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,59 +1,5 @@
#!/usr/bin/env bash

set -eu

# Set variables
SDDB_USER=user
SDDB_PASS=password
SDDB_DATABASE=default

# replicate set initiate
echo "Checking mongo container..."
until mongosh --host mongo --eval "print(\"waited for connection\")"
do
sleep 1
done

echo "Initializing replicaset..."
mongosh --host mongo <<EOF
rs.initiate(
{
_id: "rs0",
version: 1,
members: [
{ _id: 0, host: "mongo:27017"}
]
}
)
rs.status()
mongosh "mongodb://mongo/default?replicaSet=rs0&readPreference=primary" <<EOF
db.getCollectionNames().forEach(c => db.getCollection(c).drop())
EOF


echo "Creating admin user: root@root/admin"
mongosh --host mongo <<EOF
db.getSiblingDB('admin').createUser(
{
user: "root",
pwd: "root",
roles: [ { role: "root", db: "admin" } ]
}
)
rs.status()
EOF

echo "Creating normal user: ${SDDB_USER}:${SDDB_PASS}/${SDDB_DATABASE}"
mongosh --host mongo <<EOF
use ${SDDB_DATABASE}
db.createUser(
{
user: "${SDDB_USER}",
pwd: "${SDDB_PASS}",
roles: [ { role: "dbOwner", db: "${SDDB_DATABASE}" } ]
}
)
EOF

echo "Confirm normal user account"
echo "---------------------------------------"
mongosh --eval 'rs.status()' "mongodb://${SDDB_USER}:${SDDB_PASS}@mongo:27017/${SDDB_DATABASE}"
echo "---------------------------------------"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,5 @@ runtime/*
!*/*/*/.gitkeep
!*/*/*/*/.gitkeep
!*/*/*/*/*/.gitkeep
!*/*/*/*/*/*/.gitkeep
!*/*/*/*/*/*/.gitkeep
/.phpunit.cache/
17 changes: 0 additions & 17 deletions bin/command.php

This file was deleted.

4 changes: 2 additions & 2 deletions bin/console.php
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/env php
<?php

! defined('DEFAULT_TIMEZONE') && define('DEFAULT_TIMEZONE', 'UTC');
!defined('DEFAULT_TIMEZONE') && define('DEFAULT_TIMEZONE', 'UTC');

ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');

require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__.'/../vendor/autoload.php';

error_reporting(E_ALL);
date_default_timezone_set(DEFAULT_TIMEZONE);
Expand Down
11 changes: 6 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
}
],
"require": {
"php": "^8.2.0"
"php": "^8.2.0",
"ext-mongo": "*",
"mongodb/mongodb": "^1.15",
"psr/simple-cache": "^3.0"
},
"require-dev": {
"laravel/pint": "^1.8",
"mockery/mockery": "^1.6",
"pestphp/pest": "^2.5.0",
"phpstan/phpstan": "^1.10.13",
"rector/rector": "^0.15.24",
"symfony/var-dumper": "^6.2.8"
},
Expand Down Expand Up @@ -49,12 +52,10 @@
"lint": "pint",
"test:refacto": "rector --dry-run",
"test:lint": "pint --test",
"test:types": "phpstan analyse --ansi",
"test:unit": "pest --colors=always",
"test": [
"ci": [
"@test:refacto",
"@test:lint",
"@test:types",
"@test:unit"
]
}
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ services:
command: --replSet rs0
volumes:
- ./migrations/mongo:/migrations
- ./.docker/mongo:/usr/scripts
ports:
- '27017:27017'
restart: on-failure
Expand Down
19 changes: 18 additions & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,38 @@

setup: ## Setup the project
docker-compose down -v
rm -rf ./runtime/cache/*
docker-compose pull
docker-compose up -d --build --remove-orphans --force-recreate
sleep 5
@make install-dependencies
make setup-database

ci: ## Run the CI pipeline
docker-compose exec php bash -c "composer ci"

test: ## Run the tests
docker-compose exec php bash -c "composer test:unit"

install-dependencies: ## Install the project dependencies
docker-compose exec php bash -c "composer install --ignore-platform-reqs"

mongo-stream-listener: ## Start the MongoDB stream listener
docker-compose exec php bash -c "/app/bin/console.php mongo:stream-listener"

setup-database: ## Setup the database
make database-cleanup
make database-migrate

database-cleanup: ## Cleanup the database
docker-compose exec mongo bash -c "mongosh \"mongodb://mongo/default?replicaSet=rs0&readPreference=primary\" --quiet --eval 'db.getCollectionNames().forEach(c => db.getCollection(c).drop());'"
docker-compose exec mongo bash -c "/usr/scripts/reset.sh"

database-migrate: ## Migrate the database
docker-compose exec mongo bash -c "find /migrations/ -name \"*.sh\" -exec {} \;"

database-seed: ## Create a new record in the database
docker-compose exec mongo bash -c "/usr/scripts/create-new-record.sh"

playground: ## Start a PHP playground dockerized environment
@make check-docker
@docker-compose exec php bash
Expand Down
6 changes: 0 additions & 6 deletions phpstan.neon.dist

This file was deleted.

20 changes: 20 additions & 0 deletions src/Factories/CacheFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Medeirosinacio\MongoTtlIndexChangeStream\Factories;

use InvalidArgumentException;
use Medeirosinacio\MongoTtlIndexChangeStream\LocalCacheDriver;
use Psr\SimpleCache\CacheInterface;

final class CacheFactory
{
public static function make(string $driver = 'local'): CacheInterface
{
return match ($driver) {
'local' => new LocalCacheDriver(),
default => throw new InvalidArgumentException('Invalid cache driver'),
};
}
}
23 changes: 23 additions & 0 deletions src/Factories/MongoFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Medeirosinacio\MongoTtlIndexChangeStream\Factories;

use MongoDB\Client;

final class MongoFactory
{
public static function make(): Client
{
return new Client(
'mongodb://mongo:27017',
[
'username' => 'root',
'password' => 'root',
'ssl' => false,
'replicaSet' => 'rs0',
]
);
}
}
121 changes: 121 additions & 0 deletions src/LocalCacheDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

namespace Medeirosinacio\MongoTtlIndexChangeStream;

use DateInterval;
use Exception;
use Psr\SimpleCache\CacheInterface;

final class LocalCacheDriver implements CacheInterface
{
private readonly string $cacheDir;

public function __construct(string $cacheDir = '/app/runtime/cache')
{
$this->cacheDir = rtrim($cacheDir, DIRECTORY_SEPARATOR);
if (is_dir($this->cacheDir)) {
return;
}
if (mkdir($this->cacheDir, 0755, true)) {
return;
}
if (is_dir($this->cacheDir)) {
return;
}
throw new Exception('Failed to create cache directory.');
}

public function set(string $key, mixed $value, int|DateInterval|null $ttl = 3600): bool
{
$filePath = $this->getFilePath($key);
$data = [
'expires_at' => time() + $ttl,
'value' => serialize($value),
];

return (bool) file_put_contents($filePath, serialize($data));
}

public function get(string $key, mixed $default = null): mixed
{
$filePath = $this->getFilePath($key);

if (!file_exists($filePath)) {
return null;
}

$data = unserialize(file_get_contents($filePath));

if ($data['expires_at'] < time()) {
unlink($filePath);

return null;
}

return unserialize($data['value']);
}

public function delete(string $key): bool
{
$filePath = $this->getFilePath($key);

if (file_exists($filePath)) {
return unlink($filePath);
}

return false;
}

public function clear(): bool
{
$files = glob($this->cacheDir.'/*');

foreach ($files as $file) {
if (is_file($file)) {
unlink($file);
}
}

return true;
}

private function getFilePath(string $key): string
{
return $this->cacheDir.DIRECTORY_SEPARATOR.md5($key).'.cache';
}

public function getMultiple(iterable $keys, mixed $default = null): iterable
{
$items = [];
foreach ($keys as $key) {
$items[$key] = $this->get($key);
}

return $items;
}

public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool
{
foreach ($values as $key => $value) {
$this->set($key, $value, is_int($ttl) ? $ttl : 3600);
}

return true;
}

public function deleteMultiple(iterable $keys): bool
{
foreach ($keys as $key) {
$this->delete($key);
}

return true;
}

public function has(string $key): bool
{
return $this->get($key) !== null;
}
}
Loading

0 comments on commit 3671a96

Please sign in to comment.