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…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...