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在实现。结果还是一样。直到后来找到了真实原因是一个变量可变的声明,

  1. 建立图形界面,调查对比后使用slint。
  2. 提交reqwest,分form.和json数据,cookie保存登陆状态,取回response并且regex分析结果,解析json结果。
  3. 更新界面状态,使用两个线程,一个交互web server结果保存在全局变量,一个刷新全局变量到界面状态。
  4. 编码用户密码以方便登陆,用户明文到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任务。我觉得也挺好的,有容了再提交一篇。

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

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

相关文章

通用运维基础

一 网络基础 知识点:网络交换1.1 VLAN1.2VxLAN2.网络路由3.网络常用命令目标:1. 了解网络的基本概念 2. 掌握常用的网络排错命令 1、网络交换 1.1 网络虚拟化 什么是网络虚拟化 网络虚拟化是指虚拟网络节点之间的连接并不使用物理线缆连接,而是依靠特定的虚拟化链路相连…

TCP的第三次握手没有回复,会出现哪些问题现象

从三次握手的一开始来讲&#xff0c;刚开始客户端和服务器都处于close状态 这里不能是2次握手的原因就在于&#xff0c;服务器端即女孩子&#xff0c;无法确认客户端即男孩子&#xff0c;是否已经收到了&#xff0c;我也愿意建立连接即我也爱你&#xff0c;这一条最终确认的信息…

软件对比 | 历史气象数据哪里找?

中国气象网和羲和能源气象大数据平台两个平台当然没有“绝对”哪个好的说法&#xff0c;各自特点都在下图进行总结&#xff0c;到底用哪个还是根据自己需求自己抉择。 希望可以帮助到大家~

DK5V100R15ST1直插TO220F,12V 4A两个引脚同步整流芯片

高性能两个引脚同步整流芯片 DK5V100R15ST1产品 概述DK5V100R15ST1是一款简单高效率的同步整流芯片&#xff0c;只有A&#xff0c;K两个引脚&#xff0c;分别对应肖特基二极管PN管脚。芯片内部集成了100V功率NMOS管&#xff0c;可以大幅降低二极管导通损耗&#xff0c;提高整机…

.NET 6 中,使用 ActionFilterAttribute 实现 AOP(面向切面编程)

AOP概述&#xff1a;AOP&#xff08;面向切面编程&#xff09;是一种编程规范的风格&#xff0c;通过横切的思想&#xff0c;将系统功能和业务功能分离开&#xff0c;以提高代码的可维护性和清晰度。 系统功能模块&#xff1a; 1、缓存模块&#xff1a; 作用&#xff1a;提高…

拥塞控制算法的 rtt 公平性

我强调过&#xff0c;拥塞控制的核心在公平可用性&#xff0c;公平性由 buffer 动力学保证&#xff0c;而 buffer 动力学有两种表现形式&#xff1a; buffer 占比决定带宽占比&#xff0c;以 aimd 为例&#xff1b;带宽越小&#xff0c;buffer 挤兑加速比越大&#xff0c;以 b…

如何选择高品质SD卡

如何选择高品质SD卡 SD卡&#xff08;Secure Digital Memory Card&#xff09;是一种广泛使用的存储器件&#xff0c;因其快速的数据传输速度、可热插拔的特性以及较大的存储容量&#xff0c;广泛应用于各种场景&#xff0c;例如在便携式设备如智能手机、平板电脑、运动相机等…

作者分享|eDNA研究梯级水坝对浮游植物和浮游动物群落变化的影响

研究梯级水坝的影响对于了解和减轻其对环境的负面影响至关重要&#xff0c;浮游植物和浮游动物群落都对梯级水坝引起的变化尤为敏感。凌恩客户重庆师范大学生命科学学院水生态健康与环境安全实验室沈彦君课题组&#xff0c;通过eDNA宏条码技术对梯级水坝河道的浮游植物和浮游动…

uniapp实现在表单中展示多个选项,并且用户可以选择其中的一个或多个选项

前言 uni-data-checkbox是uni-app的一个组件,用于在表单中展示多个选项,并且用户可以选择其中的一个或多个选项。该组件可以通过设置不同的参数来控制选项的样式、布局和行为。 提示:以下是本篇文章正文内容,下面案例可供参考 uni-data-checkbox组件具有以下特点:: 1、跨…

威雅学校:2024线上3D艺术展精彩纷呈,让我们为孩子们的想象力喝彩!

Wycombe Abbey International Imaginarium 2024 IMAGINARIUM&#xff0c;是一个源于拉丁语的词汇&#xff0c;意为“想象的地方”或“幻想的世界”。在艺术和文化的领域中&#xff0c;它代表着展示创意、想象力和幻想的空间。 2024年度的威雅大家庭线上3D艺术展&#xff0c;正以…

ChatGLM-6B 部署与使用——打造你的专属GLM

ChatGLM-6B 部署与使用指南 ChatGLM-6B 是清华大学与智谱 AI 开源的一款对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;参数达到 62 亿&#xff0c;因其卓越的语言理解与生成能力&#xff0c;受到广泛关注。 一、在 DAMODEL 上部署 ChatGLM-6B…

Vue使用axios二次封装、解决跨域问题

1、什么是 axios 在实际开发过程中&#xff0c;浏览器通常需要和服务器端进行数据交互。而 Vue.js 并未提供与服务器端通信的接口。从 Vue.js 2.0 版本之后&#xff0c;官方推荐使用 axios 来实现 Ajax 请求。axios 是一个基于 promise 的 HTTP 客户端。 关于 promise 的详细介…

MQ入门(一):同步调用和异步调用--RabbitMQ基础入门

目录 1.初识MQ 1.1.同步调用 1.2.异步调用 1.3.技术选型 2.RabbitMQ 2.1.安装部署 2.2.RabbitMQ基本架构 2.3.收发消息 2.3.1.交换机 2.3.2.队列 2.3.3.绑定关系 2.3.4.发送消息 2.4.数据隔离 2.4.1.用户管理 2.4.2.virtual host 1.初识MQ 微服务一旦拆分&…

水面巡检船垃圾漂浮物检测系统源码分享

水面巡检船垃圾漂浮物检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

HarmonyOS异常处理实践

一、HarmonyOS应用异常处理框架 全面检测、精准记录异常传播路径、日志精简 二、FaultLog FaultLog是应用异常日志查询接口&#xff0c;提供QuerySelfFaultLog接口以查询自身故障。 JS_CRASH&#xff1a;ArkTS程序故障类型 CPP_CRASH&#xff1a;C程序故障类型 APP_FREEZE&…

ClickHouse | 查询

1 ALL 子句 2 ARRAY JOIN 使用别名 :在使用时可以为数组指定别名&#xff0c;数组元素可以通过此别名访问&#xff0c;但数组本身则通过原始名称访问 3 DISTINCT子句 DISTINCT不支持当包含有数组的列 4 FROM子句 FROM 子句指定从以下数据源中读取数据: 1.表 2.子…

学习threejs,添加环境光和点光源

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言二、&#x1f340;绘制任意字体模型…

一文读懂SpringIoC的工作原理和机制(面试经)

导览 前言IoC(Inversion of Control)必学必看1. DI&#xff08;Dependency Injection&#xff09;2. IoC核心思想3. 创建Bean的方式3.1 构造函数3.2 构造静态方法3.3 构造实例工厂方法 4 依赖注入的方式4.1 setter注入4.2 构造方法注入4.3 接口注入 结语精彩回顾 前言 我们在使…

什么是Node.js?

为什么JavaScript可以在浏览器中被执行&#xff1f; 在浏览器中我们加载了一些待执行JS代码&#xff0c;这些字符串要当中一个代码去执行&#xff0c;是因为浏览器中有JavaScript的解析引擎&#xff0c;它的存在我们的代码才能被执行。 不同的浏览器使用不同的javaScript解析引…

阴影的基本原理

1、现实中阴影的产生规则 如图所示&#xff0c;现实中的阴影产生规则是&#xff0c;在不考虑光线反射的前提下&#xff0c;当一个光源发射的一条光线遇到一个不透明物体A时&#xff0c;这条光线就不能够再继续照亮其他物体了&#xff08;物体B的一部分&#xff09;&#xff0c…