Android前端签到web迁移到rust的axum的过程-签到的重构
本次变更了以下内容:
- 为了使用之前ip2sta的ip到端点名的python,dic变量,将其存入redis hashset.使用地址/api/ip2dic 手动执行之.并且定义在/station/init,这个每天初始化redis的路径下.
- 在rust axum的route中定义/sta/ip2dic,用来得到redis字典的内容,包含值和键.
- 在前端的人名下使用了乒乓操作.点击状态切换,并把签到的人汇总到请假列. 可以请假和取消请假. 三个集合存数据.
*. 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.80.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 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)?;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.80.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是一个总页面模板.
相关文章:
Android前端签到web迁移到rust的axum的过程-签到的重构
本次变更了以下内容: 为了使用之前ip2sta的ip到端点名的python,dic变量,将其存入redis hashset.使用地址/api/ip2dic 手动执行之.并且定义在/station/init,这个每天初始化redis的路径下.在rust axum的route中定义/sta/ip2dic,用来得到redis字典的内容,包含值和键.在前端的人名…...
用户认证系统登录界面
下面是使用HTML和JavaScript实现的一个中文版登录界面,包含登录、注册和修改密码功能。注册成功后会显示提示信息,在登录成功后进入一个大大的欢迎页面。 1.代码展示 <!DOCTYPE html> <html lang"zh-CN"> <head><meta …...
Redis从入门到进阶(总结)
以下内容均以CentOS7为背景。 一、Redis安装及启动 mysql(读:2000/s;写:600/s) redis(读:10w/s;写:8w/s)通过官方给出的数据单机并发可以达到10w/s…...
【D3.js in Action 3 精译_044】5.1 饼图和环形图的创建(四):数据标签的添加
当前内容所在位置: 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段(一)5.1.2 饼图布局生成器(二)5.1.3 圆弧的绘制(三) ✔️5.1.4 数据标签的添加(四&…...
Linux的基本功能和命令
Linux的基本功能和命令 切换目录 pwd 查询当前目录地址 cd /xxx/xxx 转到目录 cd …/ 回到上一级目录 cd ./ 当前目录 创建、删除文件/文件夹 创建文件\文件夹 touch filename 创建空文件mkdir 创建目录 mkdir -p 目标目录存在也不报错mkdir -p xxx/xxx 递归创建目录…...
【Spark】Spark的两种核心Shuffle工作原理详解
Spark 的shuffle机制 一、Spark ShuffleManager 发展历程 Spark 1.1.0 之前 在 Spark 1.1.0 之前,Spark 使用 BlockStoreShuffleFetcher 来处理 Shuffle 操作。这个实现主要依赖于直接从 BlockManager 获取 Shuffle 数据,并通过网络进行交换。 Spark …...
TCP 的文化内涵
从历史和文化内涵的视角看 TCP 协议的优势和局限,这些都刻在基因里。节约和经济获得向下兼容,但这也意味着它没有浪费带宽的本意,任何相左的优化策略终将遇到无法解决的困难,大致就这样,这为设计新协议提了意见&#x…...
ASP.NET |日常开发中读写XML详解
ASP.NET |日常开发中读写XML详解 前言一、XML 概述1.1 定义和结构1.2 应用场景 二、读取 XML 文件2.1 使用XmlDocument类(DOM 方式)2.2 使用XmlReader类(流方式) 三、写入 XML 文件3.1 使用XmlDocument类3.2 使用XmlWr…...
Less和SCSS,哪个更好用?
前言 Less 和 SCSS 都是流行的 CSS 预处理器,它们的目的都是扩展 CSS 的功能,使样式表更具组织性、可维护性和可重用性。虽然它们有许多相似之处,但在语法、特性和工作方式上也存在一些差异。 Less Less 是一种动态样式表语言,…...
第一个C++程序--(蓝桥杯备考版)
第一个C程序 基础程序 #include <iostream>//头⽂件 using namespace std;//使⽤std的名字空间 int main()//main函数 {cout << "hello world!" << endl; //输出:在屏幕打印"hello world!" return 0;}main函数 main 函数是…...
NanoLog起步笔记-7-log解压过程初探
nonolog起步笔记-6-log解压过程初探 再看解压过程建立调试工程修改makefile添加新的launch项 注:重新学习nanolog的README.mdPost-Execution Log Decompressor 下面我们尝试了解,解压的过程,是如何得到文件头部的meta信息的。 再看解压过程 …...
【MySQL 进阶之路】基础语法及优化技巧
MySQL DML 基础语法及优化技巧 一、DML(数据操作语言)概述 DML 是数据库操作语言的子集,用于数据的增、删、改、查四个基本操作。MySQL 中的 DML 操作通常是指以下四种基本操作: INSERT:插入数据SELECT:…...
微信小程序做电子签名功能
文章目录 最近需求要做就记录一下。 人狠话不多,直接上功能: 直接搂代码吧,复制过去就可以用,有其他需求自己改吧改吧。 signature.wxml <!-- 电子签名页面 --> <custom-navbar title"电子签名"show-home"{{fals…...
PR的选择与移动
选择工具 可以选择序列上的剪辑,如果需要多选可以按住shift键选中多个剪辑 CtrlA:可以进行全选 编组 选中多个剪辑后“右键-编组“可以将所选的剪辑连接在一起。这时单击任意剪辑都可以选中全部 向前选择轨道工具与向后选择轨道工具 向前选择轨道工具…...
Linux系统 —— 进程系列 - 进程状态 :僵尸与孤儿
目录 1. 进程状态的概念 1.1 课本上的说法:名词提炼 1.2 运行,阻塞和挂起 1.2.1 什么叫做运行状态(running)? 1.2.2 什么叫做阻塞状态(sleeping)? 1.2.3 什么叫做挂起状态&…...
linux/centOS7用户和权限管理笔记
linux系列中可以: 配置多个用户配置多个用户组用户可以加入多个用户中 linux中关于权限的管理级别有2个级别,分别是: 针对用户的权限控制针对用户组的权限控制 一,root用户 root用户拥有最大的系统操作权限,而普通…...
使用C#基于ADO.NET编写MySQL的程序
MySQL 是一个领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在网络上特别流行。MySQL 数据库可在大多数重要的操作系统平台上使用。它可在 BSD Unix、Linux、Windows 或 Mac OS 上运行。MySQL 有两个版本:MySQL 服务器系统和 MySQL 嵌入…...
Scala函数的泛型
package hfd //泛型 //需求:你是一个程序员,老板让你写一个函数,用来获取列表中的中间元素 //List(1,2,3,4,5)>中间元素的下标长度/2 >3 //getMiddleEle object Test38_5 {def print1():Unit{println(1)}def print2(): Unit {println(…...
云轴科技ZStack亮相中国生成式AI大会上海站 展现AI Infra新势力
近日,以“智能跃进,创造无限”为主题的2024中国生成式AI大会在上海举办。本次大会由上海市人工智能行业协会指导,智东西、智猩猩共同发起,邀请了人工智能行业的顶尖嘉宾汇聚一堂,以前瞻性视角解构和把脉生成式AI的技术…...
态感知与势感知
“态感知”和“势感知”是两个人机交互中较为深奥的概念,它们虽然都与感知、认知相关,但侧重点不同。下面将从这两个概念的定义、区分以及应用领域进行解释: 1. 态感知 态感知通常指的是对事物当前状态、属性或者内在特征的感知。它强调的是在…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
day51 python CBAM注意力
目录 一、CBAM 模块简介 二、CBAM 模块的实现 (一)通道注意力模块 (二)空间注意力模块 (三)CBAM 模块的组合 三、CBAM 模块的特性 四、CBAM 模块在 CNN 中的应用 一、CBAM 模块简介 在之前的探索中…...
