114 lines
2.8 KiB
Rust
114 lines
2.8 KiB
Rust
//! A simple chat program using a ring buffer to store messages.
|
|
|
|
use anchor_lang::accounts::loader::Loader;
|
|
use anchor_lang::prelude::*;
|
|
|
|
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|
|
|
#[program]
|
|
pub mod chat {
|
|
use super::*;
|
|
|
|
pub fn create_user(ctx: Context<CreateUser>, name: String) -> Result<()> {
|
|
ctx.accounts.user.name = name;
|
|
ctx.accounts.user.authority = *ctx.accounts.authority.key;
|
|
ctx.accounts.user.bump = *ctx.bumps.get("user").unwrap();
|
|
Ok(())
|
|
}
|
|
pub fn create_chat_room(ctx: Context<CreateChatRoom>, name: String) -> Result<()> {
|
|
let given_name = name.as_bytes();
|
|
let mut name = [0u8; 280];
|
|
name[..given_name.len()].copy_from_slice(given_name);
|
|
let mut chat = ctx.accounts.chat_room.load_mut()?;
|
|
chat.name = name;
|
|
Ok(())
|
|
}
|
|
pub fn send_message(ctx: Context<SendMessage>, msg: String) -> Result<()> {
|
|
let mut chat = ctx.accounts.chat_room.load_mut()?;
|
|
chat.append({
|
|
let src = msg.as_bytes();
|
|
let mut data = [0u8; 280];
|
|
data[..src.len()].copy_from_slice(src);
|
|
Message {
|
|
from: *ctx.accounts.user.to_account_info().key,
|
|
data,
|
|
}
|
|
});
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Accounts)]
|
|
#[instruction(name: String)]
|
|
pub struct CreateUser<'info> {
|
|
#[account(
|
|
init,
|
|
seeds = [authority.key().as_ref()],
|
|
bump,
|
|
payer = authority,
|
|
space = 320,
|
|
)]
|
|
user: Account<'info, User>,
|
|
#[account(mut)]
|
|
authority: Signer<'info>,
|
|
system_program: AccountInfo<'info>,
|
|
}
|
|
|
|
#[derive(Accounts)]
|
|
pub struct CreateChatRoom<'info> {
|
|
#[account(zero)]
|
|
chat_room: Loader<'info, ChatRoom>,
|
|
}
|
|
|
|
#[derive(Accounts)]
|
|
pub struct SendMessage<'info> {
|
|
#[account(
|
|
seeds = [authority.key().as_ref()],
|
|
bump = user.bump,
|
|
has_one = authority,
|
|
)]
|
|
user: Account<'info, User>,
|
|
authority: Signer<'info>,
|
|
#[account(mut)]
|
|
chat_room: Loader<'info, ChatRoom>,
|
|
}
|
|
|
|
#[account]
|
|
pub struct User {
|
|
name: String,
|
|
authority: Pubkey,
|
|
bump: u8,
|
|
}
|
|
|
|
#[account(zero_copy)]
|
|
pub struct ChatRoom {
|
|
head: u64,
|
|
tail: u64,
|
|
name: [u8; 280], // Human readable name (char bytes).
|
|
messages: [Message; 33607], // Leaves the account at 10,485,680 bytes.
|
|
}
|
|
|
|
impl ChatRoom {
|
|
fn append(&mut self, msg: Message) {
|
|
self.messages[ChatRoom::index_of(self.head)] = msg;
|
|
if ChatRoom::index_of(self.head + 1) == ChatRoom::index_of(self.tail) {
|
|
self.tail += 1;
|
|
}
|
|
self.head += 1;
|
|
}
|
|
fn index_of(counter: u64) -> usize {
|
|
std::convert::TryInto::try_into(counter % 33607).unwrap()
|
|
}
|
|
}
|
|
|
|
#[zero_copy]
|
|
pub struct Message {
|
|
pub from: Pubkey,
|
|
pub data: [u8; 280],
|
|
}
|
|
|
|
#[error_code]
|
|
pub enum ErrorCode {
|
|
Unknown,
|
|
}
|