feat: fetch from cache if existed
Signed-off-by: Pakin <pakin.t@forth.co.th>
This commit is contained in:
parent
3043f30012
commit
03263815e6
2 changed files with 98 additions and 31 deletions
63
src/app.rs
63
src/app.rs
|
|
@ -8,10 +8,10 @@ use axum::{
|
|||
};
|
||||
use axum_macros::debug_handler;
|
||||
use git2::{Cred, FetchOptions, PushOptions, RemoteCallbacks, Repository};
|
||||
use libtbr::{models, recipe_functions::common};
|
||||
|
||||
use log::{error, info, warn};
|
||||
use redis::TypedCommands;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Value, json};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
|
|
@ -23,6 +23,8 @@ pub struct AppState {
|
|||
configures: gcm::Configure,
|
||||
repo: Arc<Mutex<Repository>>,
|
||||
redis: Arc<Mutex<redis::Client>>,
|
||||
// save already fetched path, further calls should fetch from redis instead.
|
||||
fetched: Vec<String>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
|
|
@ -45,11 +47,30 @@ struct CheckoutParams {
|
|||
}
|
||||
|
||||
async fn checkout_handler(
|
||||
State(state): State<AppState>,
|
||||
State(mut state): State<AppState>,
|
||||
Query(param): Query<CheckoutParams>,
|
||||
) -> impl IntoResponse {
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
|
||||
// quick response from redis
|
||||
if let Ok(mut rcli) = state.redis.try_lock()
|
||||
&& state
|
||||
.fetched
|
||||
.contains(¶m.path.clone().as_str().to_string())
|
||||
{
|
||||
if let Ok(res) = rcli.get(param.path.clone().as_str().to_string()) {
|
||||
match res {
|
||||
Some(res) => {
|
||||
response.insert("result".to_string(), json!(res));
|
||||
return (axum::http::StatusCode::OK, Json(json!(response)));
|
||||
}
|
||||
None => {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let repo_path = state.get_config("GIT_REPO_LOCAL_DEST");
|
||||
if repo_path.is_none() {
|
||||
response.insert(
|
||||
|
|
@ -105,12 +126,22 @@ async fn checkout_handler(
|
|||
if let Some(blob) = obj.as_blob() {
|
||||
let content = unsafe { str::from_utf8_unchecked(blob.content()) };
|
||||
response.insert("result".to_string(), json!(content.to_string()));
|
||||
|
||||
if let Ok(mut rcli) = state.redis.try_lock() {
|
||||
let _ = rcli.set(legit_path.to_string(), content.to_string());
|
||||
state.fetched.push(legit_path.to_string());
|
||||
}
|
||||
} else if let Some(tree) = obj.as_tree() {
|
||||
let dir_list = tree
|
||||
.iter()
|
||||
.map(|x| x.name().unwrap_or("").to_string())
|
||||
.collect::<Vec<String>>();
|
||||
response.insert("result".to_string(), json!(dir_list));
|
||||
|
||||
if let Ok(mut rcli) = state.redis.try_lock() {
|
||||
let _ = rcli.set(legit_path.to_string(), dir_list.join(","));
|
||||
state.fetched.push(legit_path.to_string());
|
||||
}
|
||||
} else {
|
||||
let error_log = "not obj nor tree";
|
||||
error!("{error_log}");
|
||||
|
|
@ -123,7 +154,7 @@ async fn checkout_handler(
|
|||
|
||||
async fn fetch_handler(State(state): State<AppState>) -> impl IntoResponse {
|
||||
let mut response: HashMap<String, Value> = HashMap::new();
|
||||
if let Some(repo_path) = state.get_config("GIT_REPO_LOCAL_DEST") {
|
||||
if let Some(repo_path) = state.clone().get_config("GIT_REPO_LOCAL_DEST") {
|
||||
let rpath = repo_path.clone();
|
||||
|
||||
let repo = match Repository::open_bare(rpath) {
|
||||
|
|
@ -192,12 +223,33 @@ async fn fetch_handler(State(state): State<AppState>) -> impl IntoResponse {
|
|||
);
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = broadcast_need_update_new_data_after_fetch(state.clone()).await;
|
||||
});
|
||||
|
||||
(
|
||||
axum::http::StatusCode::OK,
|
||||
Json(json!({"result": "fetch success"})),
|
||||
)
|
||||
}
|
||||
|
||||
// refetch data after request `/fetch`
|
||||
async fn broadcast_need_update_new_data_after_fetch(
|
||||
state: AppState,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// clear out saved state, user must request again
|
||||
// state.fetched.clear(); // ----> background fetch into redis
|
||||
//
|
||||
//
|
||||
let state_cl = state.clone();
|
||||
let mut rcli = state_cl.redis.try_lock()?;
|
||||
for s in state.fetched {
|
||||
let _ = rcli.publish("recipe_repo_news", s);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// { path: "/path/to/file", signature: {
|
||||
// username: "", email: ""
|
||||
// }, patch_key: "edit_id_from_redis"}
|
||||
|
|
@ -382,7 +434,7 @@ async fn apply_patch_to_file(
|
|||
}
|
||||
}
|
||||
|
||||
match serde_json::to_string(¤t_full_map.clone()) {
|
||||
match serde_json::to_string_pretty(¤t_full_map.clone()) {
|
||||
Ok(ss) => ss,
|
||||
Err(_) => String::new(),
|
||||
}
|
||||
|
|
@ -521,6 +573,7 @@ pub async fn run(config: gcm::Configure) -> gcm::StandardResult {
|
|||
config.get("REDIS_URI").unwrap_or(&"".to_string()),
|
||||
config.get("REDIS_PORT").unwrap_or(&"".to_string())
|
||||
))?)),
|
||||
fetched: Vec::new(),
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
|
|
|
|||
66
src/main.rs
66
src/main.rs
|
|
@ -4,7 +4,10 @@ use env_logger::Builder;
|
|||
use libtbr::recipe_functions::common;
|
||||
use log::info;
|
||||
|
||||
use crate::{git::setup_git_repo, reg::{heartbeat_loop, registry::registry_client::RegistryClient}};
|
||||
use crate::{
|
||||
git::setup_git_repo,
|
||||
reg::{heartbeat_loop, registry::registry_client::RegistryClient},
|
||||
};
|
||||
|
||||
mod app;
|
||||
mod gcm;
|
||||
|
|
@ -12,49 +15,60 @@ mod git;
|
|||
mod reg;
|
||||
|
||||
fn setup_log(config: gcm::Configure) -> gcm::StandardResult {
|
||||
let logfile = File::create(config.get("LOG_NAME").unwrap_or(&"run.log".to_string()))?;
|
||||
let logfile = File::create(config.get("LOG_NAME").unwrap_or(&"run.log".to_string()))?;
|
||||
|
||||
Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
|
||||
.target(env_logger::Target::Pipe(Box::new(logfile))).init();
|
||||
Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
|
||||
.target(env_logger::Target::Pipe(Box::new(logfile)))
|
||||
.init();
|
||||
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn setup_registry(config: gcm::Configure) -> gcm::StandardResult {
|
||||
let cfg_clone = config.clone();
|
||||
let register_server_address = cfg_clone.get("REGISTRY_SERVER").expect("not found registry server");
|
||||
let name = cfg_clone.get("SERVICE_NAME").expect("missing service name");
|
||||
let url = cfg_clone.get("SERVICE_URL").expect("missing service url");
|
||||
let cfg_clone = config.clone();
|
||||
let register_server_address = cfg_clone
|
||||
.get("REGISTRY_SERVER")
|
||||
.expect("not found registry server");
|
||||
let name = cfg_clone.get("SERVICE_NAME").expect("missing service name");
|
||||
let url = cfg_clone.get("SERVICE_URL").expect("missing service url");
|
||||
|
||||
let token = cfg_clone.get("REGISTRY_TOKEN").expect("token not provided");
|
||||
unsafe {
|
||||
env::set_var("REGISTRY_TOKEN", token);
|
||||
}
|
||||
let token = cfg_clone.get("REGISTRY_TOKEN").expect("token not provided");
|
||||
unsafe {
|
||||
env::set_var("REGISTRY_TOKEN", token);
|
||||
}
|
||||
|
||||
let mut client = RegistryClient::connect(register_server_address.clone()).await?;
|
||||
reg::register_service(&mut client, name, url).await;
|
||||
let mut client = RegistryClient::connect(register_server_address.clone()).await?;
|
||||
reg::register_service(&mut client, name, url).await;
|
||||
|
||||
tokio::spawn(heartbeat_loop(name.to_string(), url.to_string()));
|
||||
tokio::spawn(heartbeat_loop(name.to_string(), url.to_string()));
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> gcm::StandardResult {
|
||||
let config: gcm::Configure = common::get_config();
|
||||
setup_log(config.clone())?;
|
||||
|
||||
match std::fs::read_dir(config.get("GIT_REPO_LOCAL_DEST").expect("not exist")) {
|
||||
Ok(_) => {
|
||||
info!("GIT_REPO `{dest}` already setup", dest = config.get("GIT_REPO_LOCAL_DEST").unwrap())
|
||||
},
|
||||
Err(_) => {
|
||||
setup_git_repo(config.clone())?;
|
||||
}
|
||||
Ok(_) => {
|
||||
info!(
|
||||
"GIT_REPO `{dest}` already setup",
|
||||
dest = config.get("GIT_REPO_LOCAL_DEST").unwrap()
|
||||
)
|
||||
}
|
||||
Err(_) => {
|
||||
setup_git_repo(config.clone())?;
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
"APP VERSION: {}",
|
||||
config
|
||||
.get("CONFIG_VERSION")
|
||||
.expect("config version not defined")
|
||||
);
|
||||
|
||||
setup_registry(config.clone()).await?;
|
||||
app::run(config.clone()).await?;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue