blob: 9138df06d73ec272b64833014d18d497b6ba1ddf [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::state::models::{
CreateConsumerGroupWithId, CreatePersonalAccessTokenWithHash, CreateStreamWithId,
CreateTopicWithId, CreateUserWithId,
};
use bytes::{BufMut, BytesMut};
use iggy_binary_protocol::codes::{
CHANGE_PASSWORD_CODE, CREATE_CONSUMER_GROUP_CODE, CREATE_PARTITIONS_CODE,
CREATE_PERSONAL_ACCESS_TOKEN_CODE, CREATE_STREAM_CODE, CREATE_TOPIC_CODE, CREATE_USER_CODE,
DELETE_CONSUMER_GROUP_CODE, DELETE_PARTITIONS_CODE, DELETE_PERSONAL_ACCESS_TOKEN_CODE,
DELETE_SEGMENTS_CODE, DELETE_STREAM_CODE, DELETE_TOPIC_CODE, DELETE_USER_CODE,
PURGE_STREAM_CODE, PURGE_TOPIC_CODE, UPDATE_PERMISSIONS_CODE, UPDATE_STREAM_CODE,
UPDATE_TOPIC_CODE, UPDATE_USER_CODE,
};
use iggy_binary_protocol::requests::{
consumer_groups::DeleteConsumerGroupRequest,
partitions::{CreatePartitionsRequest, DeletePartitionsRequest},
personal_access_tokens::DeletePersonalAccessTokenRequest,
segments::DeleteSegmentsRequest,
streams::{DeleteStreamRequest, PurgeStreamRequest, UpdateStreamRequest},
topics::{DeleteTopicRequest, PurgeTopicRequest, UpdateTopicRequest},
users::{
ChangePasswordRequest, DeleteUserRequest, UpdatePermissionsRequest, UpdateUserRequest,
},
};
use iggy_binary_protocol::{WireDecode, WireEncode, WireError};
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub enum EntryCommand {
CreateStream(CreateStreamWithId),
UpdateStream(UpdateStreamRequest),
DeleteStream(DeleteStreamRequest),
PurgeStream(PurgeStreamRequest),
CreateTopic(CreateTopicWithId),
UpdateTopic(UpdateTopicRequest),
DeleteTopic(DeleteTopicRequest),
PurgeTopic(PurgeTopicRequest),
CreatePartitions(CreatePartitionsRequest),
DeletePartitions(DeletePartitionsRequest),
DeleteSegments(DeleteSegmentsRequest),
CreateConsumerGroup(CreateConsumerGroupWithId),
DeleteConsumerGroup(DeleteConsumerGroupRequest),
CreateUser(CreateUserWithId),
UpdateUser(UpdateUserRequest),
DeleteUser(DeleteUserRequest),
ChangePassword(ChangePasswordRequest),
UpdatePermissions(UpdatePermissionsRequest),
CreatePersonalAccessToken(CreatePersonalAccessTokenWithHash),
DeletePersonalAccessToken(DeletePersonalAccessTokenRequest),
}
impl WireEncode for EntryCommand {
fn encoded_size(&self) -> usize {
let inner_size = match self {
EntryCommand::CreateStream(cmd) => cmd.encoded_size(),
EntryCommand::UpdateStream(cmd) => cmd.encoded_size(),
EntryCommand::DeleteStream(cmd) => cmd.encoded_size(),
EntryCommand::PurgeStream(cmd) => cmd.encoded_size(),
EntryCommand::CreateTopic(cmd) => cmd.encoded_size(),
EntryCommand::UpdateTopic(cmd) => cmd.encoded_size(),
EntryCommand::DeleteTopic(cmd) => cmd.encoded_size(),
EntryCommand::PurgeTopic(cmd) => cmd.encoded_size(),
EntryCommand::CreatePartitions(cmd) => cmd.encoded_size(),
EntryCommand::DeletePartitions(cmd) => cmd.encoded_size(),
EntryCommand::DeleteSegments(cmd) => cmd.encoded_size(),
EntryCommand::CreateConsumerGroup(cmd) => cmd.encoded_size(),
EntryCommand::DeleteConsumerGroup(cmd) => cmd.encoded_size(),
EntryCommand::CreateUser(cmd) => cmd.encoded_size(),
EntryCommand::UpdateUser(cmd) => cmd.encoded_size(),
EntryCommand::DeleteUser(cmd) => cmd.encoded_size(),
EntryCommand::ChangePassword(cmd) => cmd.encoded_size(),
EntryCommand::UpdatePermissions(cmd) => cmd.encoded_size(),
EntryCommand::CreatePersonalAccessToken(cmd) => cmd.encoded_size(),
EntryCommand::DeletePersonalAccessToken(cmd) => cmd.encoded_size(),
};
4 + 4 + inner_size
}
fn encode(&self, buf: &mut BytesMut) {
let (code, inner_size) = match self {
EntryCommand::CreateStream(cmd) => (CREATE_STREAM_CODE, cmd.encoded_size()),
EntryCommand::UpdateStream(cmd) => (UPDATE_STREAM_CODE, cmd.encoded_size()),
EntryCommand::DeleteStream(cmd) => (DELETE_STREAM_CODE, cmd.encoded_size()),
EntryCommand::PurgeStream(cmd) => (PURGE_STREAM_CODE, cmd.encoded_size()),
EntryCommand::CreateTopic(cmd) => (CREATE_TOPIC_CODE, cmd.encoded_size()),
EntryCommand::UpdateTopic(cmd) => (UPDATE_TOPIC_CODE, cmd.encoded_size()),
EntryCommand::DeleteTopic(cmd) => (DELETE_TOPIC_CODE, cmd.encoded_size()),
EntryCommand::PurgeTopic(cmd) => (PURGE_TOPIC_CODE, cmd.encoded_size()),
EntryCommand::CreatePartitions(cmd) => (CREATE_PARTITIONS_CODE, cmd.encoded_size()),
EntryCommand::DeletePartitions(cmd) => (DELETE_PARTITIONS_CODE, cmd.encoded_size()),
EntryCommand::DeleteSegments(cmd) => (DELETE_SEGMENTS_CODE, cmd.encoded_size()),
EntryCommand::CreateConsumerGroup(cmd) => {
(CREATE_CONSUMER_GROUP_CODE, cmd.encoded_size())
}
EntryCommand::DeleteConsumerGroup(cmd) => {
(DELETE_CONSUMER_GROUP_CODE, cmd.encoded_size())
}
EntryCommand::CreateUser(cmd) => (CREATE_USER_CODE, cmd.encoded_size()),
EntryCommand::UpdateUser(cmd) => (UPDATE_USER_CODE, cmd.encoded_size()),
EntryCommand::DeleteUser(cmd) => (DELETE_USER_CODE, cmd.encoded_size()),
EntryCommand::ChangePassword(cmd) => (CHANGE_PASSWORD_CODE, cmd.encoded_size()),
EntryCommand::UpdatePermissions(cmd) => (UPDATE_PERMISSIONS_CODE, cmd.encoded_size()),
EntryCommand::CreatePersonalAccessToken(cmd) => {
(CREATE_PERSONAL_ACCESS_TOKEN_CODE, cmd.encoded_size())
}
EntryCommand::DeletePersonalAccessToken(cmd) => {
(DELETE_PERSONAL_ACCESS_TOKEN_CODE, cmd.encoded_size())
}
};
buf.put_u32_le(code);
buf.put_u32_le(inner_size as u32);
match self {
EntryCommand::CreateStream(cmd) => cmd.encode(buf),
EntryCommand::UpdateStream(cmd) => cmd.encode(buf),
EntryCommand::DeleteStream(cmd) => cmd.encode(buf),
EntryCommand::PurgeStream(cmd) => cmd.encode(buf),
EntryCommand::CreateTopic(cmd) => cmd.encode(buf),
EntryCommand::UpdateTopic(cmd) => cmd.encode(buf),
EntryCommand::DeleteTopic(cmd) => cmd.encode(buf),
EntryCommand::PurgeTopic(cmd) => cmd.encode(buf),
EntryCommand::CreatePartitions(cmd) => cmd.encode(buf),
EntryCommand::DeletePartitions(cmd) => cmd.encode(buf),
EntryCommand::DeleteSegments(cmd) => cmd.encode(buf),
EntryCommand::CreateConsumerGroup(cmd) => cmd.encode(buf),
EntryCommand::DeleteConsumerGroup(cmd) => cmd.encode(buf),
EntryCommand::CreateUser(cmd) => cmd.encode(buf),
EntryCommand::UpdateUser(cmd) => cmd.encode(buf),
EntryCommand::DeleteUser(cmd) => cmd.encode(buf),
EntryCommand::ChangePassword(cmd) => cmd.encode(buf),
EntryCommand::UpdatePermissions(cmd) => cmd.encode(buf),
EntryCommand::CreatePersonalAccessToken(cmd) => cmd.encode(buf),
EntryCommand::DeletePersonalAccessToken(cmd) => cmd.encode(buf),
}
}
}
impl WireDecode for EntryCommand {
fn decode(buf: &[u8]) -> Result<(Self, usize), WireError> {
if buf.len() < 8 {
return Err(WireError::UnexpectedEof {
offset: 0,
need: 8,
have: buf.len(),
});
}
let code = u32::from_le_bytes(buf[0..4].try_into().unwrap());
let length = u32::from_le_bytes(buf[4..8].try_into().unwrap()) as usize;
if buf.len() < 8 + length {
return Err(WireError::UnexpectedEof {
offset: 8,
need: length,
have: buf.len() - 8,
});
}
let payload = &buf[8..8 + length];
let consumed = 8 + length;
let cmd = match code {
CREATE_STREAM_CODE => {
EntryCommand::CreateStream(CreateStreamWithId::decode_from(payload)?)
}
UPDATE_STREAM_CODE => {
EntryCommand::UpdateStream(UpdateStreamRequest::decode_from(payload)?)
}
DELETE_STREAM_CODE => {
EntryCommand::DeleteStream(DeleteStreamRequest::decode_from(payload)?)
}
PURGE_STREAM_CODE => {
EntryCommand::PurgeStream(PurgeStreamRequest::decode_from(payload)?)
}
CREATE_TOPIC_CODE => {
EntryCommand::CreateTopic(CreateTopicWithId::decode_from(payload)?)
}
UPDATE_TOPIC_CODE => {
EntryCommand::UpdateTopic(UpdateTopicRequest::decode_from(payload)?)
}
DELETE_TOPIC_CODE => {
EntryCommand::DeleteTopic(DeleteTopicRequest::decode_from(payload)?)
}
PURGE_TOPIC_CODE => EntryCommand::PurgeTopic(PurgeTopicRequest::decode_from(payload)?),
CREATE_PARTITIONS_CODE => {
EntryCommand::CreatePartitions(CreatePartitionsRequest::decode_from(payload)?)
}
DELETE_PARTITIONS_CODE => {
EntryCommand::DeletePartitions(DeletePartitionsRequest::decode_from(payload)?)
}
DELETE_SEGMENTS_CODE => {
EntryCommand::DeleteSegments(DeleteSegmentsRequest::decode_from(payload)?)
}
CREATE_CONSUMER_GROUP_CODE => {
EntryCommand::CreateConsumerGroup(CreateConsumerGroupWithId::decode_from(payload)?)
}
DELETE_CONSUMER_GROUP_CODE => {
EntryCommand::DeleteConsumerGroup(DeleteConsumerGroupRequest::decode_from(payload)?)
}
CREATE_USER_CODE => EntryCommand::CreateUser(CreateUserWithId::decode_from(payload)?),
UPDATE_USER_CODE => EntryCommand::UpdateUser(UpdateUserRequest::decode_from(payload)?),
DELETE_USER_CODE => EntryCommand::DeleteUser(DeleteUserRequest::decode_from(payload)?),
CHANGE_PASSWORD_CODE => {
EntryCommand::ChangePassword(ChangePasswordRequest::decode_from(payload)?)
}
UPDATE_PERMISSIONS_CODE => {
EntryCommand::UpdatePermissions(UpdatePermissionsRequest::decode_from(payload)?)
}
CREATE_PERSONAL_ACCESS_TOKEN_CODE => EntryCommand::CreatePersonalAccessToken(
CreatePersonalAccessTokenWithHash::decode_from(payload)?,
),
DELETE_PERSONAL_ACCESS_TOKEN_CODE => EntryCommand::DeletePersonalAccessToken(
DeletePersonalAccessTokenRequest::decode_from(payload)?,
),
_ => return Err(WireError::UnknownCommand(code)),
};
Ok((cmd, consumed))
}
}
impl Display for EntryCommand {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
EntryCommand::CreateStream(command) => write!(f, "CreateStream({command})"),
EntryCommand::UpdateStream(command) => write!(f, "UpdateStream({command:?})"),
EntryCommand::DeleteStream(command) => write!(f, "DeleteStream({command:?})"),
EntryCommand::PurgeStream(command) => write!(f, "PurgeStream({command:?})"),
EntryCommand::CreateTopic(command) => write!(f, "CreateTopic({command})"),
EntryCommand::UpdateTopic(command) => write!(f, "UpdateTopic({command:?})"),
EntryCommand::DeleteTopic(command) => write!(f, "DeleteTopic({command:?})"),
EntryCommand::PurgeTopic(command) => write!(f, "PurgeTopic({command:?})"),
EntryCommand::CreatePartitions(command) => write!(f, "CreatePartitions({command:?})"),
EntryCommand::DeletePartitions(command) => write!(f, "DeletePartitions({command:?})"),
EntryCommand::DeleteSegments(command) => write!(f, "DeleteSegments({command:?})"),
EntryCommand::CreateConsumerGroup(command) => {
write!(f, "CreateConsumerGroup({command})")
}
EntryCommand::DeleteConsumerGroup(command) => {
write!(f, "DeleteConsumerGroup({command:?})")
}
EntryCommand::CreateUser(command) => write!(f, "CreateUser({command})"),
EntryCommand::UpdateUser(command) => write!(f, "UpdateUser({command:?})"),
EntryCommand::DeleteUser(command) => write!(f, "DeleteUser({command:?})"),
EntryCommand::ChangePassword(command) => write!(f, "ChangePassword({command:?})"),
EntryCommand::UpdatePermissions(command) => {
write!(f, "UpdatePermissions({command:?})")
}
EntryCommand::CreatePersonalAccessToken(command) => {
write!(f, "CreatePersonalAccessToken({command})")
}
EntryCommand::DeletePersonalAccessToken(command) => {
write!(f, "DeletePersonalAccessToken({command:?})")
}
}
}
}