Android后端签到flask迁移到rust的axum的过程-签到性能和便携

本次变更了以下内容:

  • 为了使用之前ip2sta的ip到端点名的python,dic变量,将其存入redis hashset.使用地址/api/ip2dic 手动执行之.并且定义在/station/init,这个每天初始化redis的路径下.
  • 在rust axum使用redis 连接池在test中 ip2dic,IP转端点名,转本日此端网址.
  • 在前端的人名下使用了乒乓操作.点击状态切换,并把签到的人汇总到请假列. 可以请假和取消请假. 三个集合存数据.
    *. 1端点对应的人名集合,key day/端点名
    *. 2.签到的集合,key check:端点名
    *. 3,请假的集合 key check:端点名:thin (hashset,可以存放具体内容,但没使用)
  • 最后是调整caddy的反代,需要使用 个别路径的跳转,其中rust使用全新的根路径下的子路径,但是android入口也就是获得IP并且ip2sta转到端点名的路径,定义到新的rust接口.剩下的由rust实现,移动端的功能.需要使用以下语法快.在rust规划中应该加入somepath目录,这样,调试和发布,就能通用了.
handle_path  /somepath/*
rewrite *  /somerust{path}

上个文章给出了示例redis连接池.本次在它基础扩展了几乎全部adroid,app,webkit所使用网页的实现方式,切换为axum.主要逻辑从python直接迁移.说下缺点:

  • js,html,rust, 互相掺和在一起.至今也不愿隔离.由于include ,js,bootstrap,css,.这些都在运行环境,所以的cargo run的运行时虽然可以绑定redis,但是静态文件并不能直达.需要一个解决的办法.
  • 路径的话,归结为一个统一子路径,这样容易迁移,尤其在反向代理的时候,暴露一个统一子路径就比较好了.
  • route不能如flask, /test /test/ test/:arg 定向到一个函数fn, 使用变量赋值缺省值的方式.
  • 路径下函数的调用,不太知道怎么做,所以功能的分离做起来挺费劲的.
  • 关于参数的传递有点太过神奇,不知道怎么就过去了,但是要想formt!()宏的第一个参数使用,一段文件里的内容最后怎么也无法实现,最后用了mut string的 replace.
  • 在这里插入图片描述

速度和易用性肯定有提升,但是意义不算大.还有就是,可执行文件5.7M,不要建立python.环境.小功率设备也可以.这是全部的好处了.以下是总代码.
Cargo.toml

[package]
name = "hello-axum"
version = "0.1.0"
edition = "2021"[dependencies]
axum = "0.8.0-alpha.1"
bb8 = "0.8.5"
bb8-redis = "0.17.0"
redis = "0.27.2"
tokio = { version = "1.0", features = ["full", "macros", "rt-multi-thread"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
chrono = "0.4.39"

main.rc

 use axum::{extract::{FromRef, FromRequestParts, Path, State },http::{header::HeaderValue,request::{self, Parts}, StatusCode},response::Html,routing::get,http::HeaderMap,response::Redirect,Router,
};
use std::{any::{type_name,type_name_of_val, TypeId}, result};
use bb8::{Pool, PooledConnection};
use bb8_redis::RedisConnectionManager;
use redis::AsyncCommands;
use tracing_subscriber::{fmt::format, layer::SubscriberExt, util::SubscriberInitExt};use chrono::Local;
use bb8_redis::bb8;#[tokio::main]
async fn main() {tracing_subscriber::registry().with(tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()),).with(tracing_subscriber::fmt::layer()).init();tracing::debug!("connecting to redis");let redurl="redis://ip:6379/9";let manager = RedisConnectionManager::new(redurl).unwrap();let pool = bb8::Pool::builder().build(manager).await.unwrap();{// ping the database before startinglet mut conn = pool.get().await.unwrap();conn.set::<&str, &str, ()>("foo", "barr").await.unwrap();let result: String = conn.get("foo").await.unwrap();assert_eq!(result, "barr");}tracing::debug!("successfully connected to redis and pinged it");// build our application with some routeslet app = Router::new().route("/",get(using_connection_pool_extractor),// post.(using_connection_extractor),)//.route("/rsta/{day}/{sta}", get( bsta)).route("/sta/{day}/{sta}/{person}", get( bsta)).route("/check/{sta}/{person}",get(check)).route("/test/{person}",get(test)).route("/test/",get(test)).route("/thincheck/{sta}/{person}",get(thincheck)).route("/sta/ip2sta",get(using_connection_extractor)).with_state(pool);// run itlet listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();tracing::debug!("listening on {}", listener.local_addr().unwrap());axum::serve(listener, app).await.unwrap();
}type ConnectionPool = Pool<RedisConnectionManager>;async fn using_connection_pool_extractor(State(pool): State<ConnectionPool>,
) -> Result<String, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;let result: String = conn.get("foo").await.map_err(internal_error)?;Ok(format!("端点:{}",result))
}
// my first  python route async fn test(State(pool): State<ConnectionPool>,headers: HeaderMap,Path((person)):Path<(String)>
) -> Result<Redirect, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;// let result:Vec<String>= conn.keys("*").await.map_err(internal_error)?;//let key=format!("2024-10-21/{}","衡水北");//  let key=&format!("check:{}","衡水北") ;// let result:Vec<String>= conn.lrange(key,0,-1).await.map_err(internal_error)?;// let result :Vec<String>= conn.smembers(key).await.map_err(internal_error)?;//    // Ok(format!("{:?}",headers))let mut strip="10.180.145.40:544545";if let Some(ip) = headers.get("X-Forwarded-For") {strip = std::str::from_utf8(ip.as_bytes()).map_err(internal_error)?;}
if let Some(ip) = headers.get("X-Real-IP") {strip = std::str::from_utf8(ip.as_bytes()).map_err(internal_error)?;} let mut cip =String::from(strip);cip.truncate(cip.find(":").unwrap_or(cip.len()));let ipin=conn.hexists("ip2sta", &cip).await.map_err(internal_error)?;let mut  sta=String::from("调度");if ipin{sta= conn.hget("ip2sta",&cip).await.map_err(internal_error)?;}//  datetime.date.today().strftime("%Y-%m-%d") let now = Local::now();let formatted = now.format("%Y-%m-%d").to_string();Ok(Redirect::to(&format!("/rk/sta/{}/{}/{}",formatted,&sta,&person)))
}
async fn bsta(State(pool): State<ConnectionPool>,Path((day, sta,person )): Path<(String, String,String)>
) -> Result<Html<String>, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;// let result:Vec<String>= conn.keys("*").await.map_err(internal_error)?;// let result:Vec<String>= conn.lrange(key,0,-1).await.map_err(internal_error)?;// let result :Vec<String>= conn.smembers(key).await.map_err(internal_error)?;let homebytes = include_bytes!("home.html");let  mut homestr  = String::from(std::str::from_utf8(homebytes).map_err(internal_error)?);let mut result=String::from("");if   sta.contains("&"){for ista in sta.split("&"){result.push_str( stacheck(State(pool.clone()),  &day, &ista).await?.as_str());}
} 
else
{result.push_str( stacheck(State(pool.clone()),  &day, &sta).await?.as_str());
} let cks=format!(r#"<script type="text/javascript"> function emitinfo(person,urlme){{console.log(person)window.golsocket.emit('mess',   person)location.href=urlme// fechange(person,urlme)}}
window.onload = function() {{ document.getElementById("{person}").focus();
}};  </script> <body style="background: url('/images/backgroud.jpg') no-repeat center center fixed;-moz-background-size: cover;-webkit-background-size: cover;-o-background-size: cover;background-size: cover;
" > <div class="page-header" style="width: 100%;"><h3 class="opacity-75" align=center>{sta}  会  议  签  到</h3><p align=right id=day >{day}</p>  </div>  <p>{result}</p><div style=" display: flex;justify-content: right;align-items: right;width:80%;height:70%;"><h2><span class="label label-success h5">[未签到]回到会议,将弹框⏏︎到此签到⬆️,请试按此键☛</span> </h2><img  style="width: auto" src='/images/docu2.jpg' alg="some"/></div> "#);let mark=if result.contains('V') {"nill"} else { "null"} ;     let sec = &homestr.find("{mark}").unwrap();homestr.replace_range(sec..&(sec+6),&mark);// let homestr2= &homestr1.replace("{mark}", mark);let sec = &homestr.find("{mainstr}").unwrap();homestr.replace_range(sec..&(sec+9),&cks);Ok(Html(String::from(homestr)))
}async fn stacheck(  State(pool): State<ConnectionPool> ,day:&str,sta:&str
)->   Result<String, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;//  let mut conn = pool.get().await.map_err(internal_error)?;let result:Vec<String>= conn.keys("*").await.map_err(internal_error)?;let key=format!("{day}/{sta}" );let ckey=format!("check:{}",sta);let tkey=&format!("check:{}:thin",sta);let persons:Vec<String>= conn.lrange(key,0,-1).await.map_err(internal_error)?;let checks :Vec<String>= conn.smembers(ckey).await.map_err(internal_error)?;let thins :Vec<String>=conn.hkeys(tkey).await.map_err(internal_error)?;// let re= conn.del(tkey ).await.map_err(internal_error)?;// Ok(format!("{:?}",thins))let info= if checks.len()==0 {"btn-warning"}else {"btn-light "};let mut re=format!(r#"<li class="list-group-item lh-sm " style="height: 45px" ><span class= "btn {info}"> {sta}: </span>"#);for i in persons{
//<a href="/thinks/{sta}/{i}">有事</a>  let mark= if   (&checks).contains(&i) {r#""green">V</font>]</a>"# }else   {r#""red">X</font>]</a>"#};  re.push_str(& format!(r#"<a  class="btn btn-light" href='#'  οnclick='emitinfo("{i}","/rk/check/{sta}/{i}")' id={i}> {i} [<font color={mark}<space/> "#));}re.push_str(r#"{<span class= "btn {info}">有事请单击:</span>"#);for i in &checks{let mark= if  (&thins).contains(i) {r#""blue">O</font>]</a>"# } else   {r#""green">V</font>]</a>"# };  re.push_str(& format!(r#"<a  class="btn btn-light" href='#' οnclick='emitinfo("{i}","/rk/thincheck/{sta}/{i}" )' id="{i}s"> {i} [<font color={mark}<space/> "#));}re.push_str(&format!(r#"}}<a    class="lable lable-light opacity-75  " href='#'b   sta="{sta}" id="{sta}">[more]</a><space/></li>"#));//<a    class="lable lable-light opacity-75  " href="#" sta="{sta}" id="{sta}Ok(format!("{}",re.as_str()))
}async fn thincheck(State(pool): State<ConnectionPool>,headers: HeaderMap,Path((sta, person)): Path<(String, String)>
) -> Result<Redirect, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;let tkey=&format!("check:{}:thin",sta);let onthins  = conn.hexists(tkey,&person).await.map_err(internal_error)?;if  onthins {  let result: String   =conn.hdel(tkey,&person).await.map_err(internal_error)?;}  else {let result: String = conn.hset(tkey,&person,"thin").await.map_err(internal_error)?;
}
//let def=HeaderValue::from_str(&format!("/rk/test/{}s",&person)).unwrap();
//let rurl=headers.get("referer").unwrap_or(&def).to_str().unwrap_or_default();
let rurl=&format!("/rk/test/{}s",&person);
Ok( Redirect::to( rurl))
}
async fn check(State(pool): State<ConnectionPool>,headers: HeaderMap,Path((sta, person)): Path<(String, String)>
) -> Result<Redirect, (StatusCode, String)> {let mut conn = pool.get().await.map_err(internal_error)?;let ckey=&format!("check:{}",sta);let tkey=&format!("check:{}:thin",sta);//   conn.del(ckey ).await.map_err(internal_error)?;let ischeck  = conn.sismember(ckey,&person).await.map_err(internal_error)?;if   ischeck  {let result: String   =conn.srem(ckey,&[&person]).await.map_err(internal_error)?;let result: String   =conn.hdel(tkey,&person).await.map_err(internal_error)?;}  else {let result: String = conn.sadd(ckey,&[&person]).await.map_err(internal_error)?;
}//  let def=HeaderValue::from_str(&format!("/rk/test/{}",&person)).unwrap();//let rurl=headers.get("referer").unwrap_or( &def).to_str().unwrap_or_default();let rurl=&format!("/rk/test/{}",&person);Ok( Redirect::to( rurl))
}
// we can also write a custom extractor that grabs a connection from the pool
// which setup is appropriate depends on your application
struct DatabaseConnection(PooledConnection<'static, RedisConnectionManager>);impl<S> FromRequestParts<S> for DatabaseConnection
whereConnectionPool: FromRef<S>,S: Send + Sync,
{type Rejection = (StatusCode, String);async fn from_request_parts(  _parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {let pool = ConnectionPool::from_ref(state);let conn = pool.get_owned().await.map_err(internal_error)?;Ok(Self(conn))}
}async fn using_connection_extractor(DatabaseConnection(mut conn): DatabaseConnection,
) -> Result<String, (StatusCode, String)> {conn.set::<&str, &str, ()>("station", "wjc,zhw,sd").await.unwrap();let result: String = conn.hgetall("ip2sta").await.map_err(internal_error)?;// let  result: String = conn.hset("ip2sta","10.180.133.72","宫东").await.map_err(internal_error)?;Ok(format!("{:?}",result))
} /// Utility function for mapping any error into a `500 Internal Server Error`     
/// response.
fn internal_error<E>(err: E) -> (StatusCode, String)  
whereE: std::error::Error,
{(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}

这里的home.html是一个总页面模板.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/490288.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python OCR文字识别api接口

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

.NET 6.0 中接入 Log4net 和 NLog

一、接入Log4net 1.按日期和大小混合分割日志 nuget包安装 log4net Microsoft.Extensions.Logging.Log4Net.AspNetCore 配置文件 配置文件内容为 <?xml version"1.0" encoding"utf-8"?> <log4net> <!-- Define some output appe…

编写php项目所需环境

需要编写php项目&#xff0c;需要看到编写的代码展现的效果&#xff0c;这里我选择用xampp来展现 准备工作&#xff1a; https://learncodingfast.com/how-to-install-xampp-and-brackets/#Installing_and_Running_XAMPP xampp下载地址&#xff1a;https://www.apachefriends.…

树莓派Pico火灾报警器项目:基于火焰传感器、蜂鸣器与LED的C++实现

火灾是我们生活中一个不可忽视的安全隐患,而火灾报警系统在预防火灾和保障人员安全方面起着至关重要的作用。通过嵌入式技术,我们可以实现一个简单而有效的火灾报警装置。在本项目中,我们将利用 树莓派Pico 控制 火焰传感器、LED 和 蜂鸣器,模拟火灾报警装置的工作原理。本…

数学建模问题中的多目标规划

多目标规划&#xff08;Multi-Objective Optimization, MOO&#xff09;是指在优化问题中同时优化多个相互冲突的目标函数的情况。与单目标优化问题不同&#xff0c;多目标优化的解通常不再是唯一的&#xff0c;而是一个解的集合&#xff0c;称为帕累托最优解集。这些解在所有目…

智汇云舟4个案例入选“中国联通智慧城市物联感知与AI应用案例”

12月10日&#xff0c;由中国联通智慧城市军团联合联通数字科技有限公司物联网事业部、物联中国团体组织联席会共同主办的“中国联通首届智慧城市领域物联感知与AI应用优秀案例发布交流大会”在郑州举行。大会现场对50余个优秀案例进行了集中发布与表彰。智汇云舟凭借深厚的技术…

【JavaEE】网络(1)

&#x1f435;本篇文章开始讲解计算机网络相关的知识 一、基础概念 1.1 局域网和广域网 局域网→Local Area Network→简称LAN&#xff0c;局域网是局部组建的一种私有网络&#xff0c;局域网内的主机之间可以进行网络通信&#xff0c;局域网和局域网之间在没有连接的情况不能…

Unity 模板测试透视效果(URP)

可以实现笼中窥梦和PicoVR中通过VST局部透视效果。 使用到的Shader: Shader "Unlit/StencilShader" {Properties{[IntRange]_Index("Stencil Index",Range(0,255))0}SubShader{Tags{"RenderType""Opaque""Queue""Geo…

川渝地区软件工程考研择校分析

通过最新数据分析,5所高校软件工程专业2025年考研难度从高到低预计为: 电子科技大学 >> 四川大学 > 重庆大学 ≈ 西南交通大学 > 西南大学 对于想考川渝地区985但核心目标为优先上岸的考生,建议重点考虑西南交通大学软件工程学硕。该校24届软件工程学硕实际录取1…

KeepAlive与RouterView缓存

参考 vue动态组件&#xff1c;Component&#xff1e;与&#xff1c;KeepAlive&#xff1e; KeepAlive官网介绍 缓存之keep-alive的理解和应用 Vue3Vite KeepAlive页面缓存问题 vue多级菜单(路由)导致缓存(keep-alive)失效 vue3 router-view keeperalive对于同一路径但路径…

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(五) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(四)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(四) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…

短波红外相机

短波红外相机搭载采用 SenSWIR 技术的 Sony 高灵敏度传感器&#xff0c;能捕获到400nm~1700nm范围的可见光-短波红外宽波段图像信息&#xff0c;该相机可替代传统的“可见光相机短波红外相机”双相机检测方案&#xff0c;降低系统成本、提高处理速度、扩大检测范围&#xff0c;…

系统安全——访问控制访问控制

访问控制 概念 什么是访问控制 access control 为用户对系统资源提供最大限度共享的基础上&#xff0c;对用户的访问权进行管理&#xff0c;防止对信息的非授权篡改和滥用 ​ 访问控制作用 保证用户在系统安全策略下正常工作 拒绝非法用户的非授权访问请求 拒绝合法用户越权…

封装confirm(Vue3+Ts)

文章目录 思路createApp封装confirm下周计划 思路 封装confirm首先要在以前js封装confirm的基础上进行操作 之前封装confirm的时候 是通过调用自己写的confirm函数实现弹窗的出现以及消失并进行逻辑的 那么在Vue3中怎么实现呢&#xff1f; 首先要进行调用函数进行传参的操作&a…

玉米叶病预测数据集,使用yolo,coco,voc格式人工标注,准确率可达95.7%以上, 10884张图片,可识别叶枯病,普通锈病,灰叶斑病,健康的玉米叶

玉米叶病预测数据集&#xff0c;使用yolo&#xff0c;coco&#xff0c;voc格式人工标注&#xff0c;准确率可达95.7&#xff05;以上&#xff0c; 10884张图片&#xff0c;可识别叶枯病,普通锈病&#xff0c;灰叶斑病&#xff0c;健康的玉米叶 普通锈病 灰叶斑病 健康的 叶枯病…

深入理解C++优先级队列:原理解析与代码实战

C嘎嘎探索篇&#xff1a;优先级队列&#xff1a;在数据之舞中揭开算法的艺术面纱 前言&#xff1a; 小编在前几日刚刚完成了栈和队列相关内容的书写&#xff0c;今天小编在讲一种特殊的队列&#xff0c;它的名字叫做优先级队列&#xff0c;细心的读者朋友可能会发现在queue这…

SpringBoot:快速构建微服务应用

一、SpringBoot简介 什么是SpringBoot 是由Pivotal团队提供的快速开发框架。它基于Spring框架&#xff0c;可以用于快速构建微服务应用程序。SpringBoot提供了一种快速、便捷的方式来启动和配置一个基于Spring的应用程序&#xff0c;它封装了很多常用的配置&#xff0c;简化了开…

轻量级日志管理平台:Grafana Loki搭建及应用(详细篇)

前言 Grafana Loki是Grafana Lab团队提供的一个水平可扩展、高可用性、多租户的日志聚合系统&#xff0c;与其他日志系统不同的是&#xff0c;Loki最初设计的理念是为了为日志建立标签索引&#xff0c;而非将原日志内容进行索引。 现在目前成熟的方案基本上都是&#xff1a;L…

ansible自动化运维(四)jinjia2模板

Jinjia2模板 前面说到playbook组成的时候&#xff0c;有介绍到template模块&#xff0c;而template模块对模板文件进行渲染时&#xff0c;使用的就是jinja2模板引擎&#xff0c;jinja2本身就是基于python的模板引擎&#xff0c;所以下面先来了解一下jinjia2模板的一些用法 基…