use pyo3::prelude::PyObject;
use pyo3::{PyResult, Python};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use crate::types::text::ToText;
use crate::types::{Puff, Text};
#[derive(Clone, Copy)]
pub enum Strategy {
LeastBusy,
Random,
RoundRobin,
}
#[derive(Clone)]
pub struct RuntimeConfig {
max_blocking_threads: usize,
tokio_worker_threads: usize,
python: bool,
redis: bool,
redis_pool_size: u32,
postgres_pool_size: u32,
postgres: bool,
pubsub: bool,
greenlets: bool,
env_vars: Vec<(Text, Text)>,
python_paths: Vec<Text>,
gql_module: Option<Text>,
global_state_fn: Option<Arc<dyn Fn(Python) -> PyResult<PyObject> + Send + Sync + 'static>>,
blocking_task_keep_alive: Duration,
strategy: Strategy,
}
impl RuntimeConfig {
pub fn new() -> Self {
Self::default()
}
pub fn strategy(&self) -> Strategy {
self.strategy
}
pub fn max_blocking_threads(&self) -> usize {
self.max_blocking_threads
}
pub fn tokio_worker_threads(&self) -> usize {
self.tokio_worker_threads
}
pub fn blocking_task_keep_alive(&self) -> Duration {
self.blocking_task_keep_alive
}
pub fn python(&self) -> bool {
self.python
}
pub fn redis(&self) -> bool {
self.redis
}
pub fn postgres(&self) -> bool {
self.postgres
}
pub fn redis_pool_size(&self) -> u32 {
self.redis_pool_size
}
pub fn postgres_pool_size(&self) -> u32 {
self.postgres_pool_size
}
pub fn pubsub(&self) -> bool {
self.pubsub
}
pub fn greenlets(&self) -> bool {
self.greenlets
}
pub fn gql_module(&self) -> Option<Text> {
self.gql_module.puff()
}
pub fn python_paths(&self) -> Vec<Text> {
self.python_paths.clone()
}
pub fn env_vars(&self) -> Vec<(Text, Text)> {
self.env_vars.clone()
}
pub fn apply_env_vars(&self) -> () {
for (k, v) in &self.env_vars {
std::env::set_var(k.as_str(), v.as_str())
}
}
pub fn global_state(&self) -> PyResult<PyObject> {
Python::with_gil(|py| match self.global_state_fn.clone() {
Some(r) => r(py),
None => Ok(py.None()),
})
}
pub fn set_tokio_worker_threads(self, tokio_worker_threads: usize) -> Self {
let mut new = self;
new.tokio_worker_threads = tokio_worker_threads;
new
}
pub fn set_blocking_task_keep_alive(self, blocking_task_keep_alive: Duration) -> Self {
let mut new = self;
new.blocking_task_keep_alive = blocking_task_keep_alive;
new
}
pub fn set_max_blocking_threads(self, max_blocking_threads: usize) -> Self {
let mut new = self;
new.max_blocking_threads = max_blocking_threads;
new
}
pub fn set_strategy(self, strategy: Strategy) -> Self {
let mut new = self;
new.strategy = strategy;
new
}
pub fn set_python(self, python: bool) -> Self {
let mut new = self;
new.python = python;
new
}
pub fn set_redis(self, redis: bool) -> Self {
let mut new = self;
new.redis = redis;
new
}
pub fn set_postgres(self, postgres: bool) -> Self {
let mut new = self;
new.postgres = postgres;
new
}
pub fn set_postgres_pool_size(self, pool_size: u32) -> Self {
let mut new = self;
new.postgres = true;
new.postgres_pool_size = pool_size;
new
}
pub fn set_redis_pool_size(self, pool_size: u32) -> Self {
let mut new = self;
new.redis = true;
new.redis_pool_size = pool_size;
new
}
pub fn set_pubsub(self, pubsub: bool) -> Self {
let mut new = self;
new.pubsub = pubsub;
new
}
pub fn set_greenlets(self, greenlets: bool) -> Self {
let mut new = self;
new.greenlets = greenlets;
new
}
pub fn set_gql_schema_class<T: Into<Text>>(self, schema_module_path: T) -> Self {
let mut new = self;
new.gql_module = Some(schema_module_path.into());
new
}
pub fn set_global_state_fn<F: Fn(Python) -> PyResult<PyObject> + Send + Sync + 'static>(
self,
f: F,
) -> Self {
let mut new = self;
new.global_state_fn = Some(Arc::new(f));
new
}
pub fn add_env<K: Into<Text>, V: Into<Text>>(self, k: K, v: V) -> Self {
let mut new = self;
new.env_vars.push((k.into(), v.into()));
new
}
pub fn add_cwd_to_python_path(self) -> Self {
let cwd = std::env::current_dir().expect("Could not read Current Working Directory");
let mut new = self;
new.python_paths.push(
cwd.to_str()
.expect("Could not convert path to string")
.to_text(),
);
new
}
pub fn add_python_path<T: Into<Text>>(self, path: T) -> Self {
let p: PathBuf = path
.into()
.parse()
.expect("Could not convert string to path");
let path_to_add = if p.is_relative() {
let cwd = std::env::current_dir()
.expect("Could not read Current Working Directory and path is relative.");
cwd.join(p)
} else {
p
};
let path_text = path_to_add
.to_str()
.expect("Could not convert path into a string.");
let mut new = self;
new.python_paths.push(path_text.into());
new
}
}
impl Default for RuntimeConfig {
fn default() -> Self {
RuntimeConfig {
max_blocking_threads: 1024,
tokio_worker_threads: num_cpus::get(),
python: true,
global_state_fn: None,
greenlets: true,
redis: false,
redis_pool_size: 10,
postgres_pool_size: 10,
postgres: false,
pubsub: false,
blocking_task_keep_alive: Duration::from_secs(30),
strategy: Strategy::RoundRobin,
python_paths: Vec::new(),
env_vars: Vec::new(),
gql_module: None,
}
}
}