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.mzph.cn/pingmian/63735.shtml

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

相关文章

ThinkPHP知识库文档系统源码

知识库文档系统 一款基于ThinkPHP开发的知识库文档系统&#xff0c;可用于企业工作流程的文档管理&#xff0c;结构化记录沉淀高价值信息&#xff0c;形成完整的知识体系&#xff0c;能够轻松提升知识的流转和传播效率&#xff0c;更好地成就组织和个人。为部门、团队或项目搭…

交换排序(Swap Sort)详解

交换排序Swap Sort详解 冒泡排序冒泡算法代码实现冒泡分析 快速排序快排算法代码实现快排分析 交换类排序主要是通过两两比较待排元素的关键字&#xff0c;若发现与排序要求相逆&#xff0c;则交换之。在这类排序方法中最常见的是起泡排序&#xff08;冒泡排序&#xff09;和快…

091 脉冲波形的变换与产生

00 如何获得脉冲波形 01 单稳态触发器 1.分类 2.工作特点&#xff1a; ① 电路在没有触发信号作用时处于一种稳定状态。 ② 在外来触发信号作用下&#xff0c;电路由稳态翻转到暂稳态; ③ 由于电路中RC延时环节的作用&#xff0c;暂稳态不能长保持, 经过一段时间后&#xff0c…

高级排序算法(二):归并排序与堆排序详解

引言 在上一章中&#xff0c;我们探讨了高效的快速排序及其分治思想。这一次&#xff0c;我们将继续探索两种同样重要的排序算法&#xff1a;归并排序&#xff08;Merge Sort&#xff09; 和 堆排序&#xff08;Heap Sort&#xff09;。 它们与快速排序一样&#xff0c;都是O(…

JVM调优之如何排查CPU长时间100%的问题

对于CPU长时间100%的问题&#xff0c;其实有一个比较标准的排查流程&#xff0c;现在模拟一个垃圾回收导致的cup占用率过高的排查方法。 步骤如下&#xff1a; 1.先通过top命令找到消耗cpu很高的进程id 在服务器上输入top&#xff0c;显示如下&#xff1a; 通过top命令定位到…

中间件--MongoDB部署及初始化js脚本(docker部署,docker-entrypoint-initdb.d,数据迁移,自动化部署)

一、概述 MongoDB是一种常见的Nosql数据库&#xff08;非关系型数据库&#xff09;&#xff0c;以文档&#xff08;Document&#xff09;的形式存储数据。是非关系型数据库中最像关系型数据库的一种。本篇主要介绍下部署和数据迁移。 在 MongoDB 官方镜像部署介绍中&#xff…

SkyWalking Helm Chart 4.7.0 安装、配置

https://skywalking.apache.org/events/release-apache-skywalking-kubernetes-helm-chart-4.7.0/https://github.com/apache/skywalking-helm/tree/v4.7.0https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/简介 skywalking 是分布式系统的 APM(Applicat…

HTA8998 实时音频跟踪的高效内置升压2x10W免电感立体声ABID类音频功放

1、特征 输出功率(fIN1kHz,RL4Ω&#xff0c;BTL) VBAT 4V, 2x10.6W(VOUT9V,THDN10%) VBAT 4V, 2x8.6W (VOUT9V,THDN1%) 内置升压电路模式可选择:自适应实时音频跟踪 升压(可提升播放时间50%以上)、强制升压 最大升压值可选择&#xff0c;升压限流值可设置 ACF防破音功能 D类…

时间敏感网络与工业通信的融合:光路科技电力专用交换机和TSN工业交换机亮相EP电力展

12月7日&#xff0c;第三十一届中国国际电力设备及技术展览会&#xff08;EP Shanghai 2024&#xff09;暨上海国际储能技术应用展览会在上海新国际博览中心圆满落幕。本届展会以“数字能源赋能新质生产力”为主题&#xff0c;系统地呈现了电力设备行业在技术融合、转型升级及上…

前端请求后端接口报错(blockedmixed-content),以及解决办法

报错原因&#xff1a;被浏览器拦截了&#xff0c;因为接口地址不是https的。 什么是混合内容&#xff08;Mixed Content&#xff09; 混合内容是指在同一页面中同时包含安全&#xff08;HTTPS&#xff09;和非安全&#xff08;HTTP&#xff09;资源的情况。当浏览器试图加载非…

【Golang】Go语言编程思想(六):Channel,第四节,Select

使用 Select 如果此时我们有多个 channel&#xff0c;我们想从多个 channel 接收数据&#xff0c;谁来的快先输出谁&#xff0c;此时应该怎么做呢&#xff1f;答案是使用 select&#xff1a; package mainimport "fmt"func main() {var c1, c2 chan int // c1 and …

SpringBoot【八】mybatis-plus条件构造器使用手册!

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 经过上一期的mybatis-plus 入门教学&#xff0c;想必大家对它不是非常陌生了吧&#xff0c;这期呢&#xff0c;我主要是围绕以下几点展开&#xff0c;重点给大家介绍 里…

算法-字符串-32.最长有效括号

一、题目 二、思路解析 1.思路&#xff1a; 滑动窗口&#xff01;&#xff01;&#xff01; 2.常用方法&#xff1a; 无 3.核心逻辑&#xff1a; 1.特殊情况&#xff1a;当字符串为空或不存在 if(snull||s.length()0)return 0; 2.一般情况 a.记录最长有效括符res&#xff1b;初…

9. Win11上原生运行Ubuntu

本文介绍如何在win11原生系统上运行ubuntu&#xff0c;不需要额外安装虚拟机&#xff0c;以及如何配置网络等。 1.安装正版Win11 由于正版Win11需要钱&#xff0c;网上能破解的win11可能有问题&#xff0c;但是它们的破解工具&#xff0c;却是能正常用的&#xff0c;所以&…

【CSS in Depth 2 精译_075】12.2 Web 字体简介 + 12.3 谷歌字体的用法

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 12.1.1 使用 em 还是 px12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 12.2 Web 字体 ✔️12.3 谷歌字体 ✔️12.…

【学习笔记】目前市面中手持激光雷达设备及参数汇总

手持激光雷达设备介绍 手持激光雷达设备是一种利用激光时间飞行原理来测量物体距离并构建三维模型的便携式高科技产品。它通过发射激光束并分析反射回来的激光信号&#xff0c;能够精确地获取物体的三维结构信息。这种设备以其高精度、适应各种光照环境的能力和便携性&#xf…

SQL汇总数据:聚集函数

我们经常需要汇总数据而无需实际检索出这些数据&#xff0c;为此SQL提供了专门的函数。使用这些函数&#xff0c;SQL查询能够高效地检索数据&#xff0c;以便进行分析和报表生成。这类检索的例子包括&#xff1a; 确定表中行数&#xff08;或者满足某个条件或包含某个特定值的…

Midjourney基础教程-功能界面详解

基础入门教程&#xff1a; 一.Midjourney快速入门(3步画出你的第一张图&#xff09; 注&#xff1a; 1.平台为大家设置了自动翻译&#xff0c;可以直接写中文提示词&#xff0c;自动翻译成英文。当然要求更准确&#xff0c;大家可以先翻译成英 文在输入进来。 2.提示词如何去…

初识Linux · 日志编写

目录 前言&#xff1a; 日志的简单说明 编写日志 前言&#xff1a; 在线程池部分我们纵观全文&#xff0c;可以发现全文有很多很多的IO流&#xff0c;看起来还是差点意思的&#xff0c;而我们今天提到的日志&#xff0c;是在今后的代码编写中会经常接触&#xff0c;或者说在…

微信小程序做电子签名功能

文章目录 最近需求要做就记录一下。 人狠话不多&#xff0c;直接上功能&#xff1a; 直接搂代码吧,复制过去就可以用&#xff0c;有其他需求自己改吧改吧。 signature.wxml <!-- 电子签名页面 --> <custom-navbar title"电子签名"show-home"{{fals…