1use anchor_lang::prelude::*;
2pub mod consts;
3pub mod error;
4pub mod helper;
5use consts::*;
6use error::*;
7use helper::*;
8
9type NAME = [u8; MAX_SIZE as usize];
10
11declare_id!("EVRv1mgZt3E21dCMJfXDSh5qXAwwfuJAfVy3YXxfj3xx");
12
13#[program]
14pub mod bitoku_sdk_agent {
15
16 use super::*;
17
18 pub fn init_bitoku(_ctx: Context<InitBitoku>) -> Result<()> {
19 Ok(())
20 }
21
22 pub fn register_client(ctx: Context<RegisterClient>) -> Result<u8> {
23 let mut bookkeeper = ctx.accounts.bookkeeper.load_mut()?;
24 let mut request = ctx.accounts.request.load_init()?;
25 let my_id = bookkeeper.next_id;
26 addel(&mut bookkeeper.status, my_id);
27
28 request.client_id = my_id;
29 if bookkeeper.next_id == 255 {
30 return err!(BitokuAgentError::NoAvailableClients);
31 }
32 bookkeeper.next_id += 1;
33 Ok(my_id)
34 }
35
36 pub fn remove_client(ctx: Context<DeleteClient>, client_id: u8) -> Result<()> {
37 let mut bookkeeper = ctx.accounts.bookkeeper.load_mut()?;
38
39 let bool = isel(bookkeeper.status, client_id);
40 if !bool {
41 return err!(BitokuAgentError::UnregisteredClient);
42 }
43
44 delel(&mut bookkeeper.status, client_id);
45
46 Ok(())
47 }
48
49 pub fn send_request(ctx: Context<SendRequest>, request: Request) -> Result<()> {
50 let s = request.name();
51
52 let name = String::from_utf8(s.to_vec()).unwrap();
53 if validate_name(&name.as_bytes()) == false {
54 return err!(BitokuAgentError::InvalidName);
55 }
56 let req = &mut ctx.accounts.request.load_mut()?;
57 req.requester = ctx.accounts.fee_payer.to_account_info().key();
58 req.request = request;
59 Ok(())
60 }
61}
62
63#[derive(Accounts)]
64pub struct InitBitoku<'info> {
65 #[account(mut)]
66 pub fee_payer: Signer<'info>,
67
68 #[account(init, payer= fee_payer, space=41,seeds= ["book_keeper".as_ref()], bump)]
69 pub bookkeeper: AccountLoader<'info, BookKeeper>,
70
71 pub system_program: Program<'info, System>,
72}
73
74#[derive(Accounts)]
75pub struct RegisterClient<'info> {
76 #[account(mut)]
77 pub fee_payer: Signer<'info>,
78
79 #[account(mut,seeds= ["book_keeper".as_ref()], bump)]
80 pub bookkeeper: AccountLoader<'info, BookKeeper>,
81
82 #[account(
83 init,
84 payer = fee_payer,
85 space = 8+1+32+(1+128+1),
86 seeds= ["request".as_ref(),fee_payer.key().as_ref()],
87 bump
88 )]
89 pub request: AccountLoader<'info, RequestData>,
90
91 pub system_program: Program<'info, System>,
92}
93
94#[derive(Accounts)]
95pub struct DeleteClient<'info> {
96 #[account(mut)]
97 pub fee_payer: Signer<'info>,
98
99 #[account(mut,seeds= ["book_keeper".as_ref()], bump)]
100 pub bookkeeper: AccountLoader<'info, BookKeeper>,
101
102 #[account(
103 mut,
104 close = fee_payer,
105 seeds= ["request".as_ref(),fee_payer.key().as_ref()],
106 bump
107 )]
108 pub request: AccountLoader<'info, RequestData>,
109
110 pub system_program: Program<'info, System>,
111}
112
113#[derive(Accounts)]
114pub struct SendRequest<'info> {
115 #[account(mut)]
116 pub fee_payer: Signer<'info>,
117
118 #[account(mut,seeds= ["book_keeper".as_ref()], bump)]
119 pub bookkeeper: AccountLoader<'info, BookKeeper>,
120
121 #[account(
122 mut,
123 seeds= ["request".as_ref(),fee_payer.key().as_ref()],
124 bump
125 )]
126 pub request: AccountLoader<'info, RequestData>,
127
128 pub system_program: Program<'info, System>,
129}
130
131#[account(zero_copy)]
132pub struct BookKeeper {
133 status: [u8; 32],
135 next_id: u8,
136}
137
138#[account(zero_copy)]
141pub struct RequestData {
142 client_id: u8,
143 requester: Pubkey,
144 request: Request,
145}
146
147#[derive(AnchorSerialize, AnchorDeserialize, Copy, Clone)]
148pub enum Request {
149 CreateBucket { name: [u8; 128] },
150 CreateFile { name: [u8; 128] },
151 WriteFile { name: [u8; 128], file_id: u8 },
152 CloseFile { name: [u8; 128], file_id: u8 },
153 DeleteFile { name: [u8; 128], file_id: u8 },
154 SetPosition { name: [u8; 128], file_id: u8 },
155 OpenFile { name: [u8; 128], file_id: u8 },
156 ReadFile { name: [u8; 128], file_id: u8 },
157}
158
159impl Request {
160 fn name(&self) -> NAME {
161 match self {
162 Request::CreateBucket { name } => *name,
163 Request::CreateFile { name } => *name,
164 Request::WriteFile { name, .. } => *name,
165 Request::DeleteFile { name, .. } => *name,
166 Request::CloseFile { name, .. } => *name,
167 Request::SetPosition { name, .. } => *name,
168 Request::OpenFile { name, .. } => *name,
169 Request::ReadFile { name, .. } => *name,
170 }
171 }
172}