70 lines
2.1 KiB
Gleam
70 lines
2.1 KiB
Gleam
import gleam/dict.{type Dict}
|
|
import gleam/erlang/process
|
|
import gleam/option.{type Option, None, Some}
|
|
import gleam/otp/actor
|
|
|
|
const max_requests_per_minute = 10
|
|
|
|
pub type StorageState {
|
|
StorageState(pastes: Dict(String, String), rate_limits: Dict(String, Int))
|
|
}
|
|
|
|
pub type StorageMsg {
|
|
CreatePaste(key: String, content: String, reply: process.Subject(Bool))
|
|
GetPaste(key: String, reply: process.Subject(Option(String)))
|
|
PeekPaste(key: String, reply: process.Subject(Option(String)))
|
|
CheckRateLimit(ip: String, reply: process.Subject(Bool))
|
|
ResetRateLimits
|
|
}
|
|
|
|
pub fn handle_message(state: StorageState, msg: StorageMsg) {
|
|
case msg {
|
|
CreatePaste(key, content, reply) -> {
|
|
let new_state =
|
|
StorageState(dict.insert(state.pastes, key, content), state.rate_limits)
|
|
process.send(reply, True)
|
|
actor.continue(new_state)
|
|
}
|
|
PeekPaste(key, reply) -> {
|
|
let content = case dict.get(state.pastes, key) {
|
|
Ok(value) -> Some(value)
|
|
Error(_) -> None
|
|
}
|
|
process.send(reply, content)
|
|
actor.continue(state)
|
|
}
|
|
GetPaste(key, reply) -> {
|
|
let content = case dict.get(state.pastes, key) {
|
|
Ok(value) -> Some(value)
|
|
Error(_) -> None
|
|
}
|
|
let new_pastes = dict.delete(state.pastes, key)
|
|
let new_state = StorageState(new_pastes, state.rate_limits)
|
|
process.send(reply, content)
|
|
actor.continue(new_state)
|
|
}
|
|
CheckRateLimit(ip, reply) -> {
|
|
let current_count =
|
|
dict.get(state.rate_limits, ip)
|
|
|> option.from_result
|
|
|> option.unwrap(0)
|
|
let allowed = current_count < max_requests_per_minute
|
|
let new_limits = case allowed {
|
|
True -> dict.insert(state.rate_limits, ip, current_count + 1)
|
|
False -> state.rate_limits
|
|
}
|
|
process.send(reply, allowed)
|
|
actor.continue(StorageState(state.pastes, new_limits))
|
|
}
|
|
ResetRateLimits -> {
|
|
actor.continue(StorageState(state.pastes, dict.new()))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn start() {
|
|
actor.new(StorageState(dict.new(), dict.new()))
|
|
|> actor.on_message(handle_message)
|
|
|> actor.start
|
|
}
|