Skip to content

Commit

Permalink
feat: add discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
ErwannLeRoux committed May 2, 2023
1 parent dc022bc commit 9ba31f3
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 140 deletions.
28 changes: 15 additions & 13 deletions public/js/activity.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
const activityContainer = document.querySelector('#activity')

fetch(`/api/activity`)
fetch(window.location)
.then(async response => {
const bearer = response.headers.get('x-mercure-token')

if (!bearer) return

const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]
const topic = response.headers.get('x-mercure-topic')
const hubUrl = response.headers.get('Link')
.match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]

const hub = new URL(hubUrl, window.origin);
const body = await response.json()

hub.searchParams.append('topic', body.topic)
hub.searchParams.append('topic', topic)

const options = !bearer
? {}
: {
headers: {
'Authorization': bearer,
}
}

const es = new EventSourcePolyfill(hub, {
headers: {
'Authorization': bearer,
}
})
const es = new EventSourcePolyfill(hub, options)

es.onmessage = event => {
const data = JSON.parse(event.data)
Expand All @@ -31,4 +33,4 @@ fetch(`/api/activity`)

activityContainer.append(item)
}
});
})
38 changes: 16 additions & 22 deletions public/js/dinosaur.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
const alertContainer = document.querySelector('#alert-container')
const template = document.querySelector('#dinosaur-item-template')
const dinosaurList = document.querySelector('#dinosaur-list')
const dinosaurSection = document.querySelector('#dinosaur-section')
const dinosaurId = dinosaurSection.dataset.id

fetch(`/api/dinosaurs/${dinosaurId}`)
fetch(window.location)
.then(async response => {
const bearer = response.headers.get('x-mercure-token')
const topic = response.headers.get('x-mercure-topic')
const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]

/*
* If no JWT is provided, it means that the user won't
* be able to subscribe to the updates.
*/
if (!bearer) return
const hub = new URL(hubUrl);

const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]
hub.searchParams.append('topic', topic)

const es = new EventSource(hub)

const hub = new URL(hubUrl, window.origin);
const body = await response.json()
es.onmessage = e => {
const item = document.createElement('div')

hub.searchParams.append('topic', body.topic)
item.setAttribute('class', 'alert alert-danger')
item.setAttribute('role', 'alert')

const es = new EventSourcePolyfill(hub, {
headers: {
'Authorization': bearer,
}
})
item.innerHTML = 'Dinosaur has changed !'

es.onmessage = event => console.log(event)
});
alertContainer.innerHTML = ''
alertContainer.append(item)
}
})
35 changes: 35 additions & 0 deletions public/js/dinosaurs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const alertContainer = document.querySelector('#alert-container')
const template = document.querySelector('#dinosaur-item-template')
const dinosaurList = document.querySelector('#dinosaur-list')

fetch(window.location)
.then(async response => {
const topic = response.headers.get('x-mercure-topic')
const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1]

const hub = new URL(hubUrl);

hub.searchParams.append('topic', topic)

const es = new EventSource(hub)

es.onmessage = e => {
const dinosaur = JSON.parse(e.data)

const clone = template.content.cloneNode(true)
const dinosaurTemplateNameContainer = clone.querySelector('#dinosaur-item-template-name')
const dinosaurTemplateLinkContainer = clone.querySelector('#dinosaur-item-template-link')

dinosaurTemplateNameContainer.innerHTML = dinosaur.name
dinosaurTemplateLinkContainer.href = dinosaur.link

dinosaurList.append(clone)

alertContainer.innerHTML =`<div class='alert alert-success'>Welcome to ${dinosaur.name}!</div>`

window.setTimeout(() => {
const alert = document.querySelector('.alert')
alert.parentNode.removeChild(alert)
}, 5000);
}
})
28 changes: 0 additions & 28 deletions public/js/realtime.js

This file was deleted.

13 changes: 0 additions & 13 deletions src/Controller/ActivityController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\Discovery;
use Symfony\Component\Routing\Annotation\Route;

class ActivityController extends AbstractController
Expand All @@ -18,14 +15,4 @@ public function activity(): Response
{
return $this->render('activity.html.twig');
}

#[Route('/api/activity', name: 'api_activity')]
public function apiActivity(Request $request, Discovery $discovery): Response
{
$discovery->addLink($request);

return new JsonResponse([
'topic' => 'https://dinosaur-app/activity'
]);
}
}
67 changes: 46 additions & 21 deletions src/Controller/DinosaursController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@
use App\Entity\Dinosaur;
use App\Form\Type\DinosaurType;
use App\Form\Type\SearchType;
use App\Repository\DinosaurRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mercure\Discovery;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;

class DinosaursController extends AbstractController
{
public function __construct(
private HubInterface $hub,
private RouterInterface $router
) {
}

#[Route('/dinosaurs', name: 'app_list_dinosaurs')]
public function list(Request $request, ManagerRegistry $doctrine): Response
public function list(Request $request, ManagerRegistry $doctrine, DinosaurRepository $dinosaurRepository): Response
{
$q = null;
$form = $this->createForm(SearchType::class);
Expand All @@ -32,10 +38,7 @@ public function list(Request $request, ManagerRegistry $doctrine): Response
$q = $search['q'];
}

$dinosaurs = $doctrine
->getRepository(Dinosaur::class)
->search($q)
;
$dinosaurs = $dinosaurRepository->search($q);

return $this->render('dinosaurs-list.html.twig', [
'dinosaurs' => $dinosaurs,
Expand All @@ -51,17 +54,14 @@ public function list(Request $request, ManagerRegistry $doctrine): Response
public function single(
string $id,
ManagerRegistry $doctrine,
Request $request,
Discovery $discovery
Request $request
): Response
{
$dinosaur = $doctrine
->getRepository(Dinosaur::class)
->find($id)
;

$discovery->addLink($request);

if ($dinosaur === false) {
throw $this->createNotFoundException(
'The dinosaur you are looking for does not exists.'
Expand All @@ -81,17 +81,14 @@ public function single(
public function apiSingle(
string $id,
ManagerRegistry $doctrine,
Request $request,
Discovery $discovery
Request $request
): Response
{
$dinosaur = $doctrine
->getRepository(Dinosaur::class)
->find($id)
;

$discovery->addLink($request);

if ($dinosaur === false) {
throw $this->createNotFoundException(
'The dinosaur you are looking for does not exists.'
Expand All @@ -104,16 +101,14 @@ public function apiSingle(
'gender' => $dinosaur->getGender(),
'age' => $dinosaur->getAge(),
'eyeColor' => $dinosaur->getEyesColor(),
'topic' => "http://dinosaur-app/api/dinosaurs/{$dinosaur->getId()}"
'topic' => "https://dinosaur-app/api/dinosaurs/{$dinosaur->getId()}"
]);
}

#[Route('/dinosaurs/create', name: 'app_create_dinosaur')]
public function create(
Request $request,
ManagerRegistry $doctrine,
RouterInterface $router,
HubInterface $hub
ManagerRegistry $doctrine
): Response
{
$form = $this->createForm(DinosaurType::class);
Expand All @@ -128,14 +123,18 @@ public function create(
$em->flush();

$update = new Update(
'http://localhost/dinosaurs/create',
[
'https://dinosaur-app/dinosaurs',
'https://dinosaur-app/activity'
],
json_encode([
'link' => $this->router->generate('app_single_dinosaur', ['id' => $dinosaur->getId()]),
'name' => $dinosaur->getName(),
'link' => $router->generate('app_single_dinosaur', ['id' => $dinosaur->getId()])
'message' => "{$dinosaur->getName()} has been created!"
])
);

$hub->publish($update);
$this->hub->publish($update);

$this->addFlash('success', 'The dinosaur has been created!');

Expand Down Expand Up @@ -175,6 +174,19 @@ public function edit(Request $request, int $id, ManagerRegistry $doctrine): Resp

$em->flush();

$update = new Update(
[
sprintf('https://dinosaur-app/dinosaurs/edit/%d', $id),
'https://dinosaur-app/activity'
],
json_encode([
'link' => $this->router->generate('app_single_dinosaur', ['id' => $dinosaur->getId()]),
'message' => "{$dinosaur->getName()} has been edited!"
])
);

$this->hub->publish($update);

$this->addFlash('success', 'The dinosaur has been edited!');

return $this->redirectToRoute('app_list_dinosaurs');
Expand Down Expand Up @@ -207,6 +219,19 @@ public function remove(int $id, ManagerRegistry $doctrine): Response
$em->remove($dinosaur);
$em->flush();

$update = new Update(
[
sprintf('https://dinosaur-app/dinosaurs/remove/%d', $id),
'https://dinosaur-app/activity'
],
json_encode([
'link' => $this->router->generate('app_single_dinosaur', ['id' => $id]),
'message' => "{$dinosaur->getName()} has been removed!"
])
);

$this->hub->publish($update);

$this->addFlash('success', 'The dinosaur has been removed!');

return $this->redirectToRoute('app_list_dinosaurs');
Expand Down
Loading

0 comments on commit 9ba31f3

Please sign in to comment.