RUST语言的初印象-从一个模拟登陆谈起-slint+reqwest+aes
本文就一个做了三四天的小程序讲第一次学用RUST的感受,内附代码。
了角语言
从一些渠道听说了R,这个字母挺魔性,那个文章说C++和R的团体已经上升到了宗教崇拜的高度,然后,我觉得必 有过人之处,大约10年没碰C++,只知皮毛。于是想要去学一下R,这样简写是为了方便凑合看。粗粗一打听,这语言是系统的,平台通吃,android,arm,x86.苹果,安装起来也十分方便,curl一段代码就行。除了win下要用VStuty。正好我上次python,exe化的进候安装上了。所以大约10分就安好了,拿出helloworld,cargo build,cargo run,也能通过了。后来发现R在文档和库管理这一块是不是要比C++这几十年的老 将好很多呢,虽然很久没用C++,不知道发展了没有,感叹时代真是进步太大了。R的学习资料,网上有太多电子版,网页搜索查询方便,库,文档,规范也自动, 这种方便性真是让人爽快,不说别的了,还是挺推荐一学的。
任务
以前有一个模拟访问网页的python,全套代码就在里面,就剩下要了解R的语法和库就能完成任务了。于是了解reqwest是模仿request来的就用它了。结果它总是aynsc方法,看着头大,怕是掌握不住,于是就找到了reqwest::blocking这就顺利多了。还是习惯老方法。不过完成了任务就可以尝试新的了。剩下的是cookies。好在,目前的版本一步启用,
use reqwest::blocking::Client;
let client = Client::builder().cookie_store(true).build()?;
这就具备第一个轮子了。在登陆密码的以后,来了一个成功地址,做下一步的引导,结果因为这个地址,没有mut,而初始化成了,空。造成下一步,成功后也无法更新。这就让后面的所有请求是失败的。我一开始一直在怀疑cookie不能跨域fun。因为在一个fun里是好的。为此还找了cookiestore的本地文件json在实现。结果还是一样。直到后来找到了真实原因是一个变量可变的声明,
- 建立图形界面,调查对比后使用slint。
- 提交reqwest,分form.和json数据,cookie保存登陆状态,取回response并且regex分析结果,解析json结果。
- 更新界面状态,使用两个线程,一个交互web server结果保存在全局变量,一个刷新全局变量到界面状态。
- 编码用户密码以方便登陆,用户明文到AES和MD5加密,然后post去后台。
按部就班
老实的看了几个小时的教程,参数,变量,引用,数组,字符串。发现这个言语会劲量发现错的,直到按他要求来,才能通过,当然所有语言都这样。但是还是挺喜欢他的味道。和js,python形成鲜明的对比。 fn要用什么参数,传回什么类型,都要提前说好。而且,Result,Option,这样的东西,? <>这样的字符。都有自己的用处。接下了学了要用到的regex。就像reqwest、它要实现的功能都是老的,只有工具是新的。而且说心里,它跨平台,在鸿蒙也是能跑的,而且资源这么多,多好。regex r#“”#这是原始字符。以前那些提取,基本是照样出来的。
图形界面
捎带又了角一个新的slint框架,他是跨语言的,有自己的slint文件,进行窗口程序的布局。安装也像R一样,又无声又快,只是我没在vscode上,找到可拖放的插件。 在线的倒是有一个。用了半天时间,放了两个输入,一个状态,一个计数按钮。 这是从它的github,example下载来的。cargo build,cargo run。 一下就打开了。想像有一天在鸿蒙也hell world一下。但是真想不到有什么像样的任务要做。 它的in- out变量,可以在main中,set, get。在完成了后台以后,这里有一个小难点。就是状态的适时刷新。
Cargo.toml
[package]
name = "slint-rust-template"
version = "0.1.0"
edition = "2021"# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]
slint = "1.7.2"
reqwest = { version = "0.12.7", features = ["json", "cookies","blocking","gzip"] }
tokio= {version= "1" ,features= ["full"] }
regex = "1.10.6"
#recode_rs="1.0.6"
encoding_rs="0.8.34"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
main.rs
// Prevent console window in addition to Slint window in Windows release builds when, e.g., starting the app via file manager. Ignored on other platforms.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod wjc;
use slint::Weak;
use wjc::kkuser;
use std::error::Error;
use std::sync::MutexGuard;
//use reqwest::Client;
use reqwest::blocking::Client;
use std::{thread, time::Duration};
use reqwest;
use regex::Regex;
use std::collections::HashMap;
slint::include_modules!();fn main() -> Result<(), Box<dyn Error>> {let ui = AppWindow::new()?;let handle_weak = ui.as_weak();let thread = std::thread::spawn(move || {//更新状态loop{handle_weak.upgrade_in_event_loop(move |handle|{ unsafe { handle.set_counter(kkuser::progbar);handle.set_status(kkuser::thestat.unwrap().into());}});thread::sleep(Duration::from_millis(500));}});ui.on_request_increase_value({let ui_handle = ui.as_weak();move || {let ui = ui_handle.unwrap();ui.set_counter(ui.get_counter() + 0.01);kkuser::test( );}});ui.run()?;Ok(())
}
感受一下,另一个主文件
appwindow.slint
export component AppWindow inherits Window {in-out property <float> counter: 0.42;in-out property <string> user: "";in-out property <string> status: "";in-out property <string> pass: "";callback request-increase-value();preferred-width: 600px;VerticalBox {Text {text: "用户:";}LineEdit{text<=> root.user;placeholder-text:"";}Text {text: "密码:";}LineEdit{text <=> root.pass;placeholder-text: "";}ProgressIndicator {preferred-width: 100%;height: 25px;progress <=> counter;}Text {text: "状态: \{root.status}用户: \{root.user}密码: \{root.pass}";}Button {text: "登陆";clicked => {root.request-increase-value();}}}
}
完成上线
前面的reqwest中的cookie解决以后,用了一天,折腾regex,把以前定义的两三个提取,请求,再实现了一把。 又细细看了几个regex演示。学不来,学不会, 这玩意真是和R语言一样,太复杂了。我只是按照旧方式实现了。然后,任务做成了长时的。界面就在转圈。于是在改成,后才thread前。我试着让任务和界面通信。把ui传递给,网页处理程序。结果总是不行。然后找了共享全局变量的办法,static mut &。这一串下来,把全局变量,从main,移动到了reqwest主程序的模块。让它处一个独立thread、去完成上线。上main里的ui,独立运行一个loop。长久的2秒,取一个全局变量,set给一个界面元素。到于slint 里的todolist。model这一类的代码,看得一头雾水。有点早。
在main.rs下建立wjc文件夹,作为mod在练习。建立两个文件,一个
mod.rs
pub mod kkuser;
pub mod jscrypto;
kkuser.rs
use reqwest::blocking::Client;
use reqwest;
use regex::Regex;
use std::{collections::HashMap, fmt::format};
use std::error::Error;
use reqwest::{cookie::Jar, Url};
use serde::{Deserialize, Serialize};
use std::{thread, time::Duration};
use serde_json::json;
// 共享状态
pub static mut thestat: Option< &str> = Some("");
pub static mut progbar:f32=0.001;
pub struct KKUser {active: bool,username: String,passwd: String,client: Client,}
pub fn build_kkuser(username: String, passwd: String) -> Result<KKUser,Box<dyn Error>>{let client = Client::builder().cookie_store(true).build()?;let ret= KKUser {active: false,username,passwd,client,};Ok(ret)}
impl KKUser {fn getloginurl(&self)->Result<String,Box<dyn Error>>{let re = Regex::new(r#"form_login_true" action="(.+?)""#).unwrap();let ret =self.client.get(BURL).send()?.text_with_charset("GBK")?;let cap=re.captures(&*ret).unwrap() ; println!("{:?}",&cap[1]);let id=String::from(&cap[1]);Ok(id)}pub fn login(&self )->Result<bool,Box<dyn Error >> {let id=self.getloginurl().unwrap(); // let check=self.getloginurl(&client).unwrap();let var_name = format!("{BURL}{id}");let mut map = HashMap::new();map.insert("u_dlcode", self.username.as_str());map.insert("p_dlcode", self.passwd.as_str());let ret:String = self.client.post(var_name).form(&map).send()?.text_with_charset("GBK")?;println!("{ret}\n");assert_eq!(true,ret.contains("home"));Ok(ret.to_string().contains("home"))}}
pub fn test() -> Result<(), Box<dyn Error>> {let handle= std::thread::spawn(||{let u =build_kkuser("V/JNlfP3SBG8tUJW5tIAo+UogWKJ6StCzwbt4zzm4=".to_string(), "E1Kf42cdpAwXknHXIy6eqIDhtQj85wCqwer6nUTzw".to_string()).unwrap(); let r=u.login().unwrap() ;let ee=format!("{r}");u.v_jiaru().unwrap();//更新全局变量,用时间较长。u.v_ksxx( ).unwrap() ;Ok(())}
设置密码
这个网站的密码和用户名是AES-MD5,加密的串。算法是js实现 的、为模拟用的是现在加密过的,为了真实使用,还需要有自己的加密算法。由于是浏览器 的算法,我就算是web从服务器来一个询问都是做不到的。为此大学AES一天24小时。也考虑从rust,访问js脚本和语句。用了两个库,都是失败的。虽然有声称可用的。我想,他会加大程序 的体积和依赖外部环境。失去灵动能力。无耐,rust本身,一大堆的半成品。从中总算发现一个现成的实现。其实是发现了两个,一个不含ZeroPading。是js正用的。另一个倒是含有。我算过了大概的一致参数,却不能得到一致结果。后来就想改写js到rust。https://www.codeconvert.ai/free-converter 它会转换js到R代码,在折腾了快一半的时候,深感难。后来看AES的文章说,算法和参数一样,就会有一样的结果。我就又回头比对参数。从cha数组 u8,数组,分析,第个参数,是传过去的什么值。 型号浏览器devtool。看起js的内容,那太方便。才知道刚好差不多。而rust最终给的 [u8] 不是最后js得到的,js最后很像BASE64,最后证明真是,完成后的长充40-43,用parase,解码成bytest、长度刚好32bits。这和rust取得的结果也挺像的。于是base64,处理过。js和R终于成功会合。另外就md5是套在密码外,然后给AES处理的。于是这就好办了。R有很标准的MD5. 有一个点是,处理出的结果还是 [u8].可以直接做AES的输入。但是要是拿来用,就又不对了。 感谢js的直观。它的md5,得到的u8的十六进制小写字符串。然后给了AES。这就好了,R,结果又安装了个小库, 只为了转成十六进制。看来,语言全靠外挂,怪不得可以跑嵌入式400K内存的板子。 我猜也许AI可以做到很多,我还是纯靠搜索了。
在Cargo.toml加入
[dependencies]aes="0.8.4"block-padding ="0.3.3"cbc="0.1.2" base64="0.22.1"hex-literal="0.4.1" md-5 = "0.10.6"data-encoding = "2.6.0"
在wjc目录建立新文件jscrypto.rs
在同目录下的kkuser.rs添加use super::jscrypto ;以使用其功能
//前端js,使用crypto-js对数据进行AES加密
//function js_encrypt(text){
//var key = CryptoJS.enc.Latin1.parse('1E785CMD585LLS4S');//为了避免补位,直接用16位的秘钥
// var iv = CryptoJS.enc.Latin1.parse('1234431890129056');//16位初始向量
// var encrypted = CryptoJS.AES.encrypt(text, key, {
// iv: iv,// mode:CryptoJS.mode.CBC,
// padding:CryptoJS.pad.ZeroPadding
//use std::char;
use block_padding::*;
use data_encoding::{HEXLOWER, DecodeError};
use std::error::Error;
use base64::prelude::*;use md5::{Md5, Digest};
use aes::cipher::{ BlockEncryptMut, KeyIvInit};
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;pub fn cry_AES(input: &str) -> Result<String, Box<dyn Error>> {let mut key= *b"1E785CMD585LLS4S"; let mut iv=*b"1234431890129056";let mut buf = [0u8; 48];let pt_len = input.len();buf[..pt_len].copy_from_slice(&input.as_bytes());let ct =Aes128CbcEnc::new(&key.into(), &iv.into()).encrypt_padded_mut::<ZeroPadding>(&mut buf, pt_len).unwrap();let bstr =BASE64_STANDARD.encode(ct);Ok(bstr)}
pub fn test() {let mut key= *b"1E785CMD585LLS4S"; let mut iv=*b"1234431890129056";let ct = cry_AES("username");println!("{:?}",ct.unwrap());let mut hasher = Md5::new();hasher.update(b"passwd");let mdu8 = hasher.finalize();let encoded = HEXLOWER.encode(&mdu8);println!("{:?}", cry_AES(encoded.as_str()).unwrap() );}fn main (){test();
}
整理完毕
至此完成,生成的程序10M上下,一个前台窗口,一个后台任务。点一下动一下。我是在苹果Mac上开发的,它 的虚拟机是一个win11 X64,拷贝工程前,删除了target目录,才让移动的,不然动不了。也不知道累积到了几百M、 拷贝过去,cargo build
cargo build --release ,都是干一会就好,本来也没啥内容。 把结果运行一下。换个目录再运行一下。感觉还是蛮爽的。
去年做过一个python jupyter下的,相似程序。它在server上运行,是python在wedget编程,后而传给celery任务。我觉得也挺好的,有容了再提交一篇。
相关文章:

RUST语言的初印象-从一个模拟登陆谈起-slint+reqwest+aes
本文就一个做了三四天的小程序讲第一次学用RUST的感受,内附代码。 了角语言 从一些渠道听说了R,这个字母挺魔性,那个文章说C和R的团体已经上升到了宗教崇拜的高度,然后,我觉得必 有过人之处,大约10年没碰…...
HBase批量写入优化
HBase批量写入性能优化 对于HBase的批量写入性能优化,可以考虑以下几点: 1.批量写入操作:使用HBasef的批量写入操作可以显著提高性能。将多个写入操作放在一个批次中一起提交。这样可以减少网络通信开销和减少多次写入操作的开销。方法不限。…...

江协科技STM32学习- P19 TIM编码器接口
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...

文件上传、重定向、Gin路由
文件上传 单个文件上传 index.html 文件上传前端页面代码: <!DOCTYPE html> <html lang"zh-CN"> <head><title>index</title> </head> <body> <form action"/upload" method"post"…...

躺平成长:微信小程序运营日记第二天
在进行属于生活的开源之后,自己更加感受到自己存在的渺茫,同时更加开始深刻领会,开源的重要性,在开源,开放,创造,再创新的思维模式下,不发布八部金刚功相关的训练视频,自…...

三分钟速览:Node.js 版本差异与关键特性解析
Node.js 是一个广泛使用的 JavaScript 运行时环境,允许开发者在服务器端运行 JavaScript 代码。随着技术的发展,Node.js 不断推出新版本,引入新特性和改进。了解不同版本之间的差异对于开发者来说至关重要。以下是一个快速指南,帮…...

git创建新分支
git创建新分支 1.先在gitLab上New branch. 2.本地右键git小乌 - /切换/检出-创建新分支,分支名称和上一步创建的一样。 最后记得改个文件提交下,看看gitLab上是否提交成功。...
Chip-seq数据分析处理流程
一、处理过程 要处理 SRR14879780 的 ChIP-seq 数据并进行基序分析(包括比对到参考基因组 hg38.fasta 和峰值调用),你可以按照以下步骤操作,并使用相应的代码。每个步骤会涉及一些常用的生物信息学工具,如 FastQC、Tr…...
spring boot3.2.x与spring boot2.7.x对比
Spring Boot 3.2.x 相比 Spring Boot 2.7.x 带来了许多重要的变化、新特性以及性能改进。这些新功能不仅提升了开发者的效率,还优化了应用的性能和安全性。以下是两者的主要差异、优势以及使用说明: 1. JDK 17 支持 Spring Boot 2.7.x 支持 JDK 8 至 J…...

Vue2(十三):路由
一、路由的简介 vue-rooter:是vue的一个插件库,专门用来实现SPA应用 1.对SPA应用的理解 1、单页 Web 应用(single page web application,SPA)。 2、整个应用只有一个完整的页面 index.html。 3、点击页面中的导航链…...

Java并发:互斥锁,读写锁,公平锁,Condition,StampedLock
阅读本文之前可以看一看 Java 多线程基础: Java:多线程(进程线程,线程状态,创建线程,线程操作) Java:多线程(同步死锁,锁&原子变量,线程通信&…...
在 Linux 中,要让某一个线程或进程排他性地独占一个 CPU
文章目录 1. CPU 亲和性(CPU Affinity)2. 中断隔离(IRQ Isolation)3. 系统 tickless 模式(NoHZ Mode)4. 实时调度策略5. CPU 隔离(CPU Isolation)和 Full CPU Isolation实现最低的延迟抖动在 Linux 中,要让某一个线程 排他性地独占一个 CPU,并且进一步隔离中断(包括…...
滚雪球学MySQL[7.3讲]:数据库日志与审计详解:从错误日志到审计日志的配置与使用
全文目录: 前言7.3 日志与审计1. 日志类型与配置1.1 错误日志(Error Log)配置错误日志使用场景案例演示 1.2 慢查询日志(Slow Query Log)配置慢查询日志使用场景案例演示 1.3 查询日志(General Query Log&a…...
网关的作用及其高可用性设计详解
引言 在现代分布式系统架构中,网关(Gateway)是一个关键组件。它作为客户端与后端服务之间的桥梁,不仅提供了请求路由、负载均衡、安全认证、流量控制等功能,还能够保护后端服务的安全和稳定性。网关的设计和高可用性对…...

Vortex GPGPU的github流程跑通与功能模块波形探索
文章目录 前言一、跟着官方文档走一遍二、cache子模块的波形仿真2.1 必要的文件内容解释2.2 cache子模块波形仿真——目前环境没啥问题了,就vcd因为配置问题出不来 总结 前言 看了那么久的verilog代码和文档,但还是没怎么接触过Vortex GPGPU全流程跑通与…...

10.2 Linux_并发_进程相关函数
创建子进程 函数声明如下: pid_t fork(void); 返回值:失败返回-1,成功返回两次,子进程获得0(系统分配),父进程获得子进程的pid 注意:fork创建子进程,实际上就是将父进程复制一遍作为子进程&…...

【深度学习基础模型】玻尔兹曼机BM|受限玻尔兹曼机RBM|深度置信网络DBN详细理解并附实现代码。
【深度学习基础模型】玻尔兹曼机Boltzmann machines (BM)|受限玻尔兹曼机Restricted Boltzmann machines (RBM)|深度置信网络Deep belief networks (DBN)详细理解并附实现代码。 【深度学习基础模型】玻尔兹曼机Boltzmann machines (BM)|受限玻尔兹曼机Restricted Boltzmann m…...

滑动窗口->dd爱框框
1.题目: 2.题解: 2.1为什么用滑动窗口优化: 因为元素都是大于0的 所以:当找到大于等于x的值时,right可以不用返回 两个指针都往后走;因此可以使用滑动窗口优化暴力解法 2.2:滑动窗口具体使用步…...

Python从入门到高手4.1节-掌握条件控制语句
目录 4.1.1 理解条件控制 4.1.2 if, elif, else 4.1.3 条件表达式 4.1.4 条件控制可以嵌套 4.1.5 if语句的三元运算 4.1.6 国庆节快乐 4.1.1 理解条件控制 在日常生活中,我们常喜欢说如果, "如果怎么样,那么就会怎么样"。"如果&qu…...

使用Qt实现实时数据动态绘制的折线图示例
基于Qt的 QChartView 和定时器来动态绘制折线图。它通过动画的方式逐步将数据点添加到图表上,并动态更新坐标轴的范围,提供了一个可以实时更新数据的折线图应用。以下是对代码的详细介绍及其功能解析: 代码概述 该程序使用Qt的 QChartView…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...