summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/api.md10
-rw-r--r--hi-ui/src/apiServer.js40
-rw-r--r--hi-ui/src/store/messages.js4
-rw-r--r--src/channel/event.rs29
-rw-r--r--src/channel/history.rs16
-rw-r--r--src/channel/routes/test/on_create.rs6
-rw-r--r--src/channel/routes/test/on_send.rs10
-rw-r--r--src/channel/snapshot.rs8
-rw-r--r--src/event/mod.rs54
-rw-r--r--src/event/sequence.rs4
-rw-r--r--src/message/event.rs22
-rw-r--r--src/message/history.rs14
-rw-r--r--src/message/snapshot.rs10
-rw-r--r--src/test/fixtures/event.rs8
-rw-r--r--src/test/fixtures/filter.rs6
15 files changed, 106 insertions, 135 deletions
diff --git a/docs/api.md b/docs/api.md
index 13e71c7..73bfb38 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -200,7 +200,8 @@ The returned event stream is a sequence of events:
```json
id: 1233
data: {
-data: "type": "created",
+data: "type": "channel",
+data: "event": "created",
data: "at": "2024-09-27T23:18:10.208147Z",
data: "id": "C9876cyyz",
data: "name": "example channel 2"
@@ -209,6 +210,7 @@ data: }
id: 1234
data: {
data: "type": "message",
+data: "event": "sent",
data: "at": "2024-09-27T23:19:10.208147Z",
data: "channel": {
data: "id": "C9876cyyz",
@@ -224,19 +226,21 @@ data: }
id: 1235
data: {
+data: "type": "message",
+data: "event": "deleted",
data: "at": "2024-09-28T02:44:27.077355Z",
data: "channel": {
data: "id": "C9876cyyz",
data: "name": "example channel 2"
data: },
-data: "type": "message_deleted",
data: "id": "M1312acab"
data: }
id: 1236
data: {
+data: "type": "channel",
+data: "event": "deleted",
data: "at": "2024-09-28T03:40:25.384318Z",
-data: "type": "deleted",
data: "id": "C9876cyyz"
data: }
diff --git a/hi-ui/src/apiServer.js b/hi-ui/src/apiServer.js
index ec94e82..648edf5 100644
--- a/hi-ui/src/apiServer.js
+++ b/hi-ui/src/apiServer.js
@@ -55,22 +55,36 @@ export function subscribeToEvents(resume_point) {
const data = JSON.parse(evt.data);
switch (data.type) {
- case 'created':
- channelsList.update((value) => value.addChannel(data.id, data.name))
+ case 'channel':
+ onChannelEvent(data);
break;
case 'message':
- messages.update((value) => value.addMessage(data));
- break;
- case 'message_deleted':
- messages.update((value) => value.deleteMessage(data.channel.id, data.id));
- break;
- case 'deleted':
- activeChannel.update((value) => value.deleteChannel(data.id));
- channelsList.update((value) => value.deleteChannel(data.id));
- messages.update((value) => value.deleteChannel(data.id));
- break;
- default:
+ onMessageEvent(data);
break;
}
}
}
+
+function onChannelEvent(data) {
+ switch (data.event) {
+ case 'created':
+ channelsList.update((value) => value.addChannel(data.id, data.name))
+ break;
+ case 'deleted':
+ activeChannel.update((value) => value.deleteChannel(data.id));
+ channelsList.update((value) => value.deleteChannel(data.id));
+ messages.update((value) => value.deleteChannel(data.id));
+ break;
+ }
+}
+
+function onMessageEvent(data) {
+ switch (data.event) {
+ case 'sent':
+ messages.update((value) => value.addMessage(data));
+ break;
+ case 'deleted':
+ messages.update((value) => value.deleteMessage(data.channel.id, data.id));
+ break;
+ }
+}
diff --git a/hi-ui/src/store/messages.js b/hi-ui/src/store/messages.js
index 560b9e1..cefd725 100644
--- a/hi-ui/src/store/messages.js
+++ b/hi-ui/src/store/messages.js
@@ -24,8 +24,8 @@ export class Messages {
deleteMessage(channel, message) {
- let messages = this.messages(channel).filter((msg) => msg.message.id != message);
- this.channels[channel] = messages;
+ this.updateChannel(channel, (messages) => messages.filter((msg) => msg.id != message));
+ return this;
}
deleteChannel(id) {
diff --git a/src/channel/event.rs b/src/channel/event.rs
index 9f2e263..f3dca3e 100644
--- a/src/channel/event.rs
+++ b/src/channel/event.rs
@@ -5,33 +5,30 @@ use crate::{
};
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-pub struct Event {
- #[serde(flatten)]
- pub instant: Instant,
- #[serde(flatten)]
- pub kind: Kind,
+#[serde(tag = "event", rename_all = "snake_case")]
+pub enum Event {
+ Created(Created),
+ Deleted(Deleted),
}
impl Sequenced for Event {
fn instant(&self) -> Instant {
- self.instant
+ match self {
+ Self::Created(event) => event.instant,
+ Self::Deleted(event) => event.instant,
+ }
}
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-#[serde(tag = "type", rename_all = "snake_case")]
-pub enum Kind {
- Created(Created),
- Deleted(Deleted),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct Created {
#[serde(flatten)]
+ pub instant: Instant,
+ #[serde(flatten)]
pub channel: Channel,
}
-impl From<Created> for Kind {
+impl From<Created> for Event {
fn from(event: Created) -> Self {
Self::Created(event)
}
@@ -39,10 +36,12 @@ impl From<Created> for Kind {
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct Deleted {
+ #[serde(flatten)]
+ pub instant: Instant,
pub id: channel::Id,
}
-impl From<Deleted> for Kind {
+impl From<Deleted> for Event {
fn from(event: Deleted) -> Self {
Self::Deleted(event)
}
diff --git a/src/channel/history.rs b/src/channel/history.rs
index 0499927..78b3437 100644
--- a/src/channel/history.rs
+++ b/src/channel/history.rs
@@ -40,22 +40,20 @@ impl History {
}
fn created(&self) -> Event {
- Event {
+ Created {
instant: self.created,
- kind: Created {
- channel: self.channel.clone(),
- }
- .into(),
+ channel: self.channel.clone(),
}
+ .into()
}
fn deleted(&self) -> Option<Event> {
- self.deleted.map(|instant| Event {
- instant,
- kind: Deleted {
+ self.deleted.map(|instant| {
+ Deleted {
+ instant,
id: self.channel.id.clone(),
}
- .into(),
+ .into()
})
}
}
diff --git a/src/channel/routes/test/on_create.rs b/src/channel/routes/test/on_create.rs
index ed49017..8c3c62b 100644
--- a/src/channel/routes/test/on_create.rs
+++ b/src/channel/routes/test/on_create.rs
@@ -2,7 +2,7 @@ use axum::extract::{Json, State};
use futures::stream::StreamExt as _;
use crate::{
- channel::{app, routes},
+ channel::{self, app, routes},
event,
test::fixtures::{self, future::Immediately as _},
};
@@ -53,8 +53,8 @@ async fn new_channel() {
.expect("creation event published");
assert!(matches!(
- event.kind,
- event::Kind::ChannelCreated(event)
+ event,
+ event::Event::Channel(channel::Event::Created(event))
if event.channel == response_channel
));
}
diff --git a/src/channel/routes/test/on_send.rs b/src/channel/routes/test/on_send.rs
index 3297093..d2acc48 100644
--- a/src/channel/routes/test/on_send.rs
+++ b/src/channel/routes/test/on_send.rs
@@ -4,8 +4,8 @@ use futures::stream::StreamExt;
use crate::{
channel,
channel::routes,
- event,
- message::app::SendError,
+ event::{self, Sequenced},
+ message::{self, app::SendError},
test::fixtures::{self, future::Immediately as _},
};
@@ -53,10 +53,10 @@ async fn messages_in_order() {
let events = events.collect::<Vec<_>>().immediately().await;
for ((sent_at, message), event) in requests.into_iter().zip(events) {
- assert_eq!(*sent_at, event.instant.at);
+ assert_eq!(*sent_at, event.at());
assert!(matches!(
- event.kind,
- event::Kind::MessageSent(event)
+ event,
+ event::Event::Message(message::Event::Sent(event))
if event.message.sender == sender
&& event.message.body == message
));
diff --git a/src/channel/snapshot.rs b/src/channel/snapshot.rs
index afef2fb..d4d1d27 100644
--- a/src/channel/snapshot.rs
+++ b/src/channel/snapshot.rs
@@ -1,5 +1,5 @@
use super::{
- event::{Created, Event, Kind},
+ event::{Created, Event},
Id,
};
@@ -11,9 +11,9 @@ pub struct Channel {
impl Channel {
fn apply(state: Option<Self>, event: Event) -> Option<Self> {
- match (state, event.kind) {
- (None, Kind::Created(event)) => Some(event.into()),
- (Some(channel), Kind::Deleted(event)) if channel.id == event.id => None,
+ match (state, event) {
+ (None, Event::Created(event)) => Some(event.into()),
+ (Some(channel), Event::Deleted(event)) if channel.id == event.id => None,
(state, event) => panic!("invalid channel event {event:#?} for state {state:#?}"),
}
}
diff --git a/src/event/mod.rs b/src/event/mod.rs
index e748d66..698e55a 100644
--- a/src/event/mod.rs
+++ b/src/event/mod.rs
@@ -15,63 +15,29 @@ pub use self::{
pub type ResumePoint = Option<Sequence>;
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-pub struct Event {
- #[serde(flatten)]
- pub instant: Instant,
- #[serde(flatten)]
- pub kind: Kind,
+#[serde(tag = "type", rename_all = "snake_case")]
+pub enum Event {
+ Channel(channel::Event),
+ Message(message::Event),
}
impl Sequenced for Event {
fn instant(&self) -> Instant {
- self.instant
+ match self {
+ Self::Channel(event) => event.instant(),
+ Self::Message(event) => event.instant(),
+ }
}
}
impl From<channel::Event> for Event {
fn from(event: channel::Event) -> Self {
- Self {
- instant: event.instant,
- kind: event.kind.into(),
- }
+ Self::Channel(event)
}
}
impl From<message::Event> for Event {
fn from(event: message::Event) -> Self {
- Self {
- instant: event.instant(),
- kind: event.kind.into(),
- }
- }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-#[serde(tag = "type", rename_all = "snake_case")]
-pub enum Kind {
- #[serde(rename = "created")]
- ChannelCreated(channel::event::Created),
- #[serde(rename = "message")]
- MessageSent(message::event::Sent),
- MessageDeleted(message::event::Deleted),
- #[serde(rename = "deleted")]
- ChannelDeleted(channel::event::Deleted),
-}
-
-impl From<channel::event::Kind> for Kind {
- fn from(kind: channel::event::Kind) -> Self {
- match kind {
- channel::event::Kind::Created(created) => Self::ChannelCreated(created),
- channel::event::Kind::Deleted(deleted) => Self::ChannelDeleted(deleted),
- }
- }
-}
-
-impl From<message::event::Kind> for Kind {
- fn from(kind: message::event::Kind) -> Self {
- match kind {
- message::event::Kind::Sent(created) => Self::MessageSent(created),
- message::event::Kind::Deleted(deleted) => Self::MessageDeleted(deleted),
- }
+ Self::Message(event)
}
}
diff --git a/src/event/sequence.rs b/src/event/sequence.rs
index ceb5bcb..bf6d5b8 100644
--- a/src/event/sequence.rs
+++ b/src/event/sequence.rs
@@ -72,6 +72,10 @@ impl Sequence {
pub trait Sequenced {
fn instant(&self) -> Instant;
+ fn at(&self) -> DateTime {
+ self.instant().at
+ }
+
fn sequence(&self) -> Sequence {
self.instant().into()
}
diff --git a/src/message/event.rs b/src/message/event.rs
index 712ecc1..9f49a32 100644
--- a/src/message/event.rs
+++ b/src/message/event.rs
@@ -5,25 +5,13 @@ use crate::{
};
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-pub struct Event {
- #[serde(flatten)]
- pub kind: Kind,
-}
-
-impl Sequenced for Event {
- fn instant(&self) -> Instant {
- self.kind.instant()
- }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
-#[serde(tag = "type", rename_all = "snake_case")]
-pub enum Kind {
+#[serde(tag = "event", rename_all = "snake_case")]
+pub enum Event {
Sent(Sent),
Deleted(Deleted),
}
-impl Sequenced for Kind {
+impl Sequenced for Event {
fn instant(&self) -> Instant {
match self {
Self::Sent(sent) => sent.instant(),
@@ -44,7 +32,7 @@ impl Sequenced for Sent {
}
}
-impl From<Sent> for Kind {
+impl From<Sent> for Event {
fn from(event: Sent) -> Self {
Self::Sent(event)
}
@@ -64,7 +52,7 @@ impl Sequenced for Deleted {
}
}
-impl From<Deleted> for Kind {
+impl From<Deleted> for Event {
fn from(event: Deleted) -> Self {
Self::Deleted(event)
}
diff --git a/src/message/history.rs b/src/message/history.rs
index 3c3f77a..b5886af 100644
--- a/src/message/history.rs
+++ b/src/message/history.rs
@@ -35,22 +35,20 @@ impl History {
// Events interface
impl History {
fn sent(&self) -> Event {
- Event {
- kind: Sent {
- message: self.message.clone(),
- }
- .into(),
+ Sent {
+ message: self.message.clone(),
}
+ .into()
}
fn deleted(&self) -> Option<Event> {
- self.deleted.map(|instant| Event {
- kind: Deleted {
+ self.deleted.map(|instant| {
+ Deleted {
instant,
channel: self.message.channel.clone(),
id: self.message.id.clone(),
}
- .into(),
+ .into()
})
}
diff --git a/src/message/snapshot.rs b/src/message/snapshot.rs
index a06fbc4..a8cf734 100644
--- a/src/message/snapshot.rs
+++ b/src/message/snapshot.rs
@@ -1,12 +1,12 @@
use super::{
- event::{Event, Kind, Sent},
+ event::{Event, Sent},
Id,
};
use crate::{channel::Channel, event::Instant, login::Login};
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct Message {
- #[serde(skip)]
+ #[serde(flatten)]
pub sent: Instant,
pub channel: Channel,
pub sender: Login,
@@ -16,9 +16,9 @@ pub struct Message {
impl Message {
fn apply(state: Option<Self>, event: Event) -> Option<Self> {
- match (state, event.kind) {
- (None, Kind::Sent(event)) => Some(event.into()),
- (Some(message), Kind::Deleted(event)) if message.id == event.id => None,
+ match (state, event) {
+ (None, Event::Sent(event)) => Some(event.into()),
+ (Some(message), Event::Deleted(event)) if message.id == event.id => None,
(state, event) => panic!("invalid message event {event:#?} for state {state:#?}"),
}
}
diff --git a/src/test/fixtures/event.rs b/src/test/fixtures/event.rs
index 09f0490..7fe2bf3 100644
--- a/src/test/fixtures/event.rs
+++ b/src/test/fixtures/event.rs
@@ -1,11 +1,11 @@
use crate::{
- event::{Event, Kind},
- message::Message,
+ event::Event,
+ message::{Event::Sent, Message},
};
pub fn message_sent(event: &Event, message: &Message) -> bool {
matches!(
- &event.kind,
- Kind::MessageSent(event) if message == &event.into()
+ &event,
+ Event::Message(Sent(event)) if message == &event.into()
)
}
diff --git a/src/test/fixtures/filter.rs b/src/test/fixtures/filter.rs
index 6e62aea..84d27b0 100644
--- a/src/test/fixtures/filter.rs
+++ b/src/test/fixtures/filter.rs
@@ -1,11 +1,11 @@
use futures::future;
-use crate::event::{Event, Kind};
+use crate::{channel::Event::Created, event::Event, message::Event::Sent};
pub fn messages() -> impl FnMut(&Event) -> future::Ready<bool> {
- |event| future::ready(matches!(event.kind, Kind::MessageSent(_)))
+ |event| future::ready(matches!(event, Event::Message(Sent(_))))
}
pub fn created() -> impl FnMut(&Event) -> future::Ready<bool> {
- |event| future::ready(matches!(event.kind, Kind::ChannelCreated(_)))
+ |event| future::ready(matches!(event, Event::Channel(Created(_))))
}