1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2024-12-29 02:57:35 +02:00

Удален tcpc, доработана вк Mongo

This commit is contained in:
Anton Titovets 2024-12-10 17:27:37 +03:00
parent c88357604f
commit c39aef4ecf
10 changed files with 666 additions and 812 deletions

View File

@ -0,0 +1,3 @@
[target.x86_64-unknown-linux-gnu]
linker = "C:/msys64/mingw64/bin/x86_64-w64-mingw32-gcc.exe"
rustc-linker = "C:/msys64/mingw64/bin/x86_64-w64-mingw32-gcc.exe"

View File

@ -3,6 +3,8 @@ name = "opi_mongodb"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
@ -11,6 +13,7 @@ lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
opt-level = "z"
[dependencies]
addin1c = "0.5.0"
@ -20,6 +23,7 @@ serde_json = "1.0.133"
[dependencies.mongodb]
version = "2.0.0"
version = "=2.8.2"
default-features = false
features = ["sync"]

View File

@ -0,0 +1,2 @@
cargo build --release --target x86_64-pc-windows-msvc
cargo build --release --target x86_64-unknown-linux-gnu

View File

@ -1,84 +1,557 @@
use mongodb::{options::ClientOptions, bson::{doc, Document}};
use mongodb::sync::{Client, Collection};
use serde_json::Value;
use mongodb::{options::{ClientOptions, FindOptions}, bson::{doc, Document}};
use mongodb::sync::{Client, Collection, Database};
use serde_json::{json, Value};
pub struct MongoClient {
client: Client,
}
impl MongoClient {
// СЛУЖЕБНЫЕ МЕТОДЫ ----------------------------------------------------------------------------
// Конструктор для создания клиента
pub fn new(uri: &str) -> MongoClient {
match ClientOptions::parse(uri) {
Ok(client_options) => match Client::with_options(client_options) {
Ok(client) => MongoClient { client },
Err(_) => MongoClient { client: Client::with_options(ClientOptions::default()).unwrap() }, // Возвращаем дефолтный клиент в случае ошибки
Err(_) => MongoClient { client: Client::with_options(ClientOptions::default()).unwrap() },
},
Err(_) => MongoClient { client: Client::with_options(ClientOptions::default()).unwrap() }, // Возвращаем дефолтный клиент в случае ошибки
Err(_) => MongoClient { client: Client::with_options(ClientOptions::default()).unwrap() },
}
}
// Синхронный метод для вставки данных, возвращающий строку или ошибку
// Вспомогательная функция для формирования JSON ответа
fn make_response(ok: bool, data: &str) -> String {
json!({
"ok": ok,
"data": data
})
.to_string()
}
// ОСНОВНЫЕ МЕТОДЫ -----------------------------------------------------------------------------
// РАБОТА С БАЗАМИ ДАННЫХ ----------------------------------------------------------------------
// Получение списка баз
pub fn list_databases(&self) -> String {
match self.client.list_database_names(None, None) {
Ok(databases) =>
Self::make_response(
true,
&format!("{:?}", databases)),
Err(err) =>
Self::make_response(
false,
&format!("Failed to list databases: {}", err)),
}
}
// Получение статистики базы данных
pub fn database_stats(&self, db_name: &str) -> String {
let db = self.client.database(db_name);
match db.run_command(doc! { "dbStats": 1 }, None) {
Ok(stats) =>
Self::make_response(
true,
&format!("{:?}", stats)),
Err(err) =>
Self::make_response(
false,
&format!("Failed to get database stats for '{}': {}", db_name, err)),
}
}
// Удаление базы
pub fn drop_database(&self, db_name: &str) -> String {
match self.client.database(db_name).drop(None) {
Ok(_) =>
Self::make_response(
true,
&format!("Database '{}' dropped successfully", db_name)),
Err(err) =>
Self::make_response(
false,
&format!("Failed to drop database '{}': {}", db_name, err)),
}
}
// Проверка существования базы
pub fn database_exists(&self, db_name: &str) -> bool {
// Получаем список всех баз данных
let db_list = match self.client.list_databases(None, None) {
Ok(databases) => databases,
Err(_) => return false, // Если ошибка при получении списка баз, возвращаем false
};
// Проверяем, есть ли указанная база данных в списке
db_list.iter().any(|db| db.name == db_name)
}
// РАБОТА С КОЛЛЕКЦИЯМИ ------------------------------------------------------------------------
// Получение списка коллекций
pub fn list_collections(&self, db_name: &str) -> String {
let db: Database = self.client.database(db_name);
match db.list_collection_names(None) {
Ok(collection_names) => {
// Преобразуем список коллекций в JSON
let collections_json = serde_json::to_string(&collection_names).unwrap();
Self::make_response(true, &collections_json)
}
Err(err) => Self::make_response(false, &format!("Failed to list collections: {}", err)),
}
}
// Создание коллекции в базе данных
pub fn create_collection(&self, db_name: &str, collection_name: &str) -> String {
let db = self.client.database(db_name);
match db.create_collection(collection_name, None) {
Ok(_) => Self::make_response(
true,
&format!("Collection '{}' created successfully in database '{}'", collection_name, db_name)),
Err(err) =>
Self::make_response(
false,
&format!("Failed to create collection '{}': {}", collection_name, err)),
}
}
// Удаление коллекции из базы данных
pub fn drop_collection(&self, db_name: &str, collection_name: &str) -> String {
let collection = self.client.database(db_name).collection::<Document>(collection_name);
match collection.drop(None) {
Ok(_) =>
Self::make_response(
true,
&format!("Collection '{}' dropped successfully from database '{}'", collection_name, db_name)),
Err(err) =>
Self::make_response(
false,
&format!("Failed to drop collection '{}': {}", collection_name, err)),
}
}
// Проверка, существует ли коллекция
pub fn collection_exists(&self, db_name: &str, collection_name: &str) -> String {
match self.client.database(db_name).list_collection_names(None) {
Ok(collections) => {
if collections.contains(&collection_name.to_string()) {
Self::make_response(
true,
&format!("Collection '{}' exists in database '{}'", collection_name, db_name))
} else {
Self::make_response(
false,
&format!("Collection '{}' does not exist in database '{}'", collection_name, db_name))
}
}
Err(err) =>
Self::make_response(
false,
&format!("Failed to list collections: {}", err)),
}
}
// РАБОТА С ДОКУМЕНТАМИ ------------------------------------------------------------------------
// ДОБАВЛЕНИЕ ДОКУМЕНТОВ -----------------------------------------------------------------------
// Метод для вставки одного документа
pub fn insert_data(&self, db_name: &str, collection_name: &str, data: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Преобразуем строку JSON в объект
let json_value: Value = match serde_json::from_str(data) {
Ok(value) => value,
Err(err) => return format!("Failed to parse JSON: {}", err),
Err(err) =>
return Self::make_response(
false,
&format!("Failed to parse JSON: {}", err)),
};
// Преобразуем объект JSON в BSON
let bson_document = match bson::to_bson(&json_value) {
Ok(bson) => bson,
Err(err) => return format!("Failed to convert to BSON: {}", err),
Err(err) =>
return Self::make_response(
false,
&format!("Failed to convert to BSON: {}", err)),
};
// Вставляем BSON документ в коллекцию
match collection.insert_one(bson_document.as_document().unwrap(), None) {
Ok(_) => "Insert successful".to_string(),
Err(err) => format!("Insert failed: {}", err),
Ok(_) =>
Self::make_response(
true,
"Insert successful"),
Err(err) =>
Self::make_response(
false,
&format!("Insert failed: {}", err)),
}
}
// Синхронный метод для поиска данных, возвращающий строку или ошибку
// Метод для вставки нескольких документов
pub fn insert_many(&self, db_name: &str, collection_name: &str, data: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
let json_values: Vec<Value> = match serde_json::from_str(data) {
Ok(values) => values,
Err(err) =>
return Self::make_response(
false,
&format!("Failed to parse JSON array: {}", err)),
};
let bson_documents: Vec<Document> = match json_values
.into_iter()
.map(|value| bson::to_bson(&value))
.collect::<Result<Vec<_>, _>>()
{
Ok(bson_array) => bson_array
.into_iter()
.filter_map(|bson| bson.as_document().cloned())
.collect(),
Err(err) =>
return Self::make_response(
false,
&format!("Failed to convert JSON to BSON: {}", err)),
};
match collection.insert_many(bson_documents, None) {
Ok(result) =>
Self::make_response(
true,
&format!("Insert successful: {} documents inserted", result.inserted_ids.len())),
Err(err) =>
Self::make_response(
false,
&format!("Insert failed: {}", err)),
}
}
// ОБНОВЛЕНИЕ ДОКУМЕНТОВ -----------------------------------------------------------------------
// Обновление одного документа в коллекции
pub fn update_data(&self, db_name: &str, collection_name: &str, query: &str, update: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Парсим JSON в структуру Value
let bson_query: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
let bson_update: Value = match serde_json::from_str(update) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse update JSON: {}", err)),
};
// Преобразуем в BSON документы
let bson_query_doc = bson::to_document(&bson_query).unwrap();
let bson_update_doc = bson::to_document(&bson_update).unwrap();
// Преобразуем в UpdateModifications
let update_modifications = doc! {
"$set": bson_update_doc
};
// Обновляем один документ
match collection.update_one(bson_query_doc, update_modifications, None) {
Ok(_) => Self::make_response(true, "Update successful"),
Err(err) => Self::make_response(false, &format!("Update failed: {}", err)),
}
}
// Обновление нескольких документов
pub fn update_many(&self, db_name: &str, collection_name: &str, query: &str, update: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Парсим JSON в структуру Value
let bson_query: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
let bson_update: Value = match serde_json::from_str(update) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse update JSON: {}", err)),
};
// Преобразуем в BSON документы
let bson_query_doc = bson::to_document(&bson_query).unwrap();
let bson_update_doc = bson::to_document(&bson_update).unwrap();
// Преобразуем в UpdateModifications
let update_modifications = doc! {"$set": bson_update_doc};
// Обновляем все документы, которые соответствуют запросу
match collection.update_many(bson_query_doc, update_modifications, None) {
Ok(result) => Self::make_response(
true,
&format!("Update successful: {} documents updated", result.modified_count)
),
Err(err) => Self::make_response(false, &format!("Update failed: {}", err)),
}
}
// УДАЛЕНИЕ ДОКУМЕНТОВ -------------------------------------------------------------------------
// Удаление одного документа
pub fn delete_data(&self, db_name: &str, collection_name: &str, query: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Преобразуем строку JSON в объект
let query_value: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
// Преобразуем объект JSON в BSON
let bson_query = match bson::to_bson(&query_value) {
Ok(bson) => bson,
Err(err) => return Self::make_response(false, &format!("Failed to convert query to BSON: {}", err)),
};
// Проверяем, что BSON является документом
match bson_query.as_document() {
Some(bson_query_doc) => {
// Удаляем один документ
match collection.delete_one(bson_query_doc.clone(), None) {
Ok(result) => {
if result.deleted_count > 0 {
Self::make_response(true, "Delete successful")
} else {
Self::make_response(false, "No documents matched the query")
}
}
Err(err) => Self::make_response(false, &format!("Delete failed: {}", err)),
}
}
None => Self::make_response(false, "Query is not a valid BSON document"),
}
}
// Удаление нескольких документов
pub fn delete_many(&self, db_name: &str, collection_name: &str, query: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Преобразуем строку JSON в объект
let query_value: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
// Преобразуем объект JSON в BSON
let bson_query = match bson::to_bson(&query_value) {
Ok(bson) => bson,
Err(err) => return Self::make_response(false, &format!("Failed to convert query to BSON: {}", err)),
};
// Проверяем, что BSON является документом
match bson_query.as_document() {
Some(bson_query_doc) => {
// Удаляем несколько документов
match collection.delete_many(bson_query_doc.clone(), None) {
Ok(result) => Self::make_response(
true,
&format!("Delete successful: {} documents deleted", result.deleted_count),
),
Err(err) => Self::make_response(false, &format!("Delete failed: {}", err)),
}
}
None => Self::make_response(false, "Query is not a valid BSON document"),
}
}
// ПОИСК ДОКУМЕНТОВ ----------------------------------------------------------------------------
// Поиск одного документа
pub fn find_data(&self, db_name: &str, collection_name: &str, query: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
let filter = doc! { "name": query };
match collection.find_one(filter, None) {
Ok(Some(doc)) => match doc.get_str("name") {
Ok(name) => name.to_string(),
Err(_) => "Error reading name from document".to_string(),
},
Ok(None) => "Document not found".to_string(),
Err(err) => format!("Find failed: {}", err),
Ok(Some(doc)) => Self::make_response(true, &format!("{:?}", doc)),
Ok(None) => Self::make_response(false, "Document not found"),
Err(err) => Self::make_response(false, &format!("Find failed: {}", err)),
}
}
// Синхронный метод для подсчета документов, возвращающий количество или ошибку
pub fn count_documents(&self, db_name: &str, collection_name: &str) -> i32 {
// Поиск нескольких документов с пагинацией
pub fn find_many(&self, db_name: &str, collection_name: &str, query: &str, page: i32, page_size: i32) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
match collection.count_documents(None, None) {
Ok(count) => count as i32,
Err(_) => -1, // Возвращаем -1 в случае ошибки
// Парсим JSON в структуру Value
let bson_query: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
// Преобразуем JSON в BSON документ
let bson_query_doc = match bson::to_document(&bson_query) {
Ok(doc) => doc,
Err(err) => return Self::make_response(false, &format!("Failed to convert query to BSON: {}", err)),
};
// Создаем параметры запроса с пагинацией
let skip = page * page_size;
let find_options = FindOptions::builder()
.skip(skip as u64) // Пропустить количество документов
.limit(page_size as i64) // Ограничить количество документов
.build();
// Выполняем поиск
let cursor = match collection.find(bson_query_doc, find_options) {
Ok(cursor) => cursor,
Err(err) => return Self::make_response(false, &format!("Find failed: {}", err)),
};
// Собираем все документы из курсора в вектор
let mut results = Vec::new();
for result in cursor {
match result {
Ok(doc) => results.push(doc),
Err(err) => return Self::make_response(false, &format!("Error iterating documents: {}", err)),
}
}
// Преобразуем документы в JSON строку
let json_results = match serde_json::to_string(&results) {
Ok(json) => json,
Err(err) => return Self::make_response(false, &format!("Failed to convert documents to JSON: {}", err)),
};
Self::make_response(true, &json_results)
}
// Синхронный метод для проверки наличия документа, возвращающий булево результат
pub fn document_exists(&self, db_name: &str, collection_name: &str, query: &str) -> bool {
// Поиск всех документов с пагинацией
pub fn find_all(&self, db_name: &str, collection_name: &str, query: &str, page: i32, page_size: i32) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Парсим JSON в структуру Value
let bson_query: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
// Преобразуем JSON в BSON документ
let bson_query_doc = match bson::to_document(&bson_query) {
Ok(doc) => doc,
Err(err) => return Self::make_response(false, &format!("Failed to convert query to BSON: {}", err)),
};
// Создаем параметры запроса с пагинацией
let skip = page * page_size;
let find_options = FindOptions::builder()
.skip(skip as u64) // Пропустить количество документов
.limit(page_size as i64) // Ограничить количество документов
.build();
// Выполняем поиск
let cursor = match collection.find(bson_query_doc, find_options) {
Ok(cursor) => cursor,
Err(err) => return Self::make_response(false, &format!("Find failed: {}", err)),
};
// Собираем все документы из курсора в вектор
let mut results = Vec::new();
for result in cursor {
match result {
Ok(doc) => results.push(doc),
Err(err) => return Self::make_response(false, &format!("Error iterating documents: {}", err)),
}
}
// Преобразуем документы в JSON строку
let json_results = match serde_json::to_string(&results) {
Ok(json) => json,
Err(err) => return Self::make_response(false, &format!("Failed to convert documents to JSON: {}", err)),
};
Self::make_response(true, &json_results)
}
// Проверка существования документа
pub fn document_exists(&self, db_name: &str, collection_name: &str, query: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
let filter = doc! { "name": query };
match collection.find_one(filter, None) {
Ok(Some(_)) => true,
Ok(None) => false,
Err(_) => false, // Возвращаем false в случае ошибки
Ok(Some(_)) => Self::make_response(true, "true"),
Ok(None) => Self::make_response(false, "false"),
Err(err) => Self::make_response(false, &format!("Check failed: {}", err)),
}
}
// Количество документов в коллекции
pub fn count_documents(&self, db_name: &str, collection_name: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
match collection.count_documents(None, None) {
Ok(count) => Self::make_response(true, &count.to_string()),
Err(err) => Self::make_response(false, &format!("Count failed: {}", err)),
}
}
// ДРУГОЕ --------------------------------------------------------------------------------------
// Произвольный запрос
pub fn run_custom_query(&self, db_name: &str, query: &str) -> String {
let db = self.client.database(db_name);
// Парсим строку запроса в BSON
let bson_query: Value = match serde_json::from_str(query) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse query JSON: {}", err)),
};
let bson_query_doc = match bson::to_document(&bson_query) {
Ok(doc) => doc,
Err(err) => return Self::make_response(false, &format!("Failed to convert query to BSON: {}", err)),
};
// Выполнение произвольного запроса
match db.run_command(bson_query_doc, None) {
Ok(result) => Self::make_response(true, &format!("{:?}", result)),
Err(err) => Self::make_response(false, &format!("Query execution failed: {}", err)),
}
}
// Агрегация
pub fn aggregate(&self, db_name: &str, collection_name: &str, pipeline: &str) -> String {
let collection: Collection<Document> = self.client.database(db_name).collection(collection_name);
// Парсим строку JSON в массив стадий агрегации
let bson_pipeline: Vec<Document> = match serde_json::from_str(pipeline) {
Ok(value) => value,
Err(err) => return Self::make_response(false, &format!("Failed to parse pipeline JSON: {}", err)),
};
// Выполняем агрегацию
let cursor = match collection.aggregate(bson_pipeline, None) {
Ok(cursor) => cursor,
Err(err) => return Self::make_response(false, &format!("Aggregation failed: {}", err)),
};
// Собираем результат в вектор
let mut result: Vec<Value> = Vec::new();
for document in cursor {
match document {
Ok(doc) => result.push(serde_json::to_value(doc).unwrap()),
Err(err) => return Self::make_response(false, &format!("Failed to read document: {}", err)),
}
}
// Возвращаем результат как строку
Self::make_response(true, &serde_json::to_string(&result).unwrap())
}
}

View File

@ -7,20 +7,54 @@ use crate::core::getset;
// Синонимы
pub const METHODS: &[&[u16]] = &[
name!("InsertData"), // 2
name!("FindData"), // 3
name!("CountDocuments"), // 4
name!("DocumentExists"), // 5
name!("ListDatabases"), // 0
name!("DatabaseStats"), // 1
name!("DropDatabase"), // 2
name!("DatabaseExists"), // 3
name!("ListCollections"), // 4
name!("CreateCollection"), // 5
name!("DropCollection"), // 6
name!("CollectionExists"), // 7
name!("InsertData"), // 8
name!("InsertMany"), // 9
name!("UpdateData"), // 10
name!("UpdateMany"), // 11
name!("DeleteData"), // 12
name!("DeleteMany"), // 13
name!("FindData"), // 14
name!("FindMany"), // 15
name!("FindAll"), // 16
name!("DocumentExists"), // 17
name!("CountDocuments"), // 18
name!("RunCustomQuery"), // 19
name!("Aggregate"), // 20
];
// Число параметров функций компоненты
pub fn get_params_amount(num: usize) -> usize {
match num {
0 => 3,
1 => 3,
2 => 2,
3 => 2,
_ => 0,
0 => 0, // list_databases (нет параметров)
1 => 1, // database_stats
2 => 1, // drop_database
3 => 1, // database_exists
4 => 1, // list_collections
5 => 2, // create_collection
6 => 2, // drop_collection
7 => 2, // collection_exists
8 => 3, // insert_data
9 => 3, // insert_many
10 => 4, // update_data
11 => 4, // update_many
12 => 3, // delete_data
13 => 3, // delete_many
14 => 3, // find_data
15 => 5, // find_many
16 => 5, // find_all
17 => 3, // document_exists
18 => 2, // count_documents
19 => 2, // run_custom_query
20 => 3, // aggregate
_ => 0, // по умолчанию 0
}
}
@ -32,44 +66,125 @@ pub fn cal_func(obj: &AddIn, num: usize, params: &mut [Variant]) -> Box<dyn crat
let client = methods::MongoClient::new(address);
match num {
0 => {
0 => { // list_databases
Box::new(client.list_databases())
},
1 => { // database_stats
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name= params[1].get_string().unwrap_or(String::new());
Box::new(client.database_stats(&db_name))
},
2 => { // drop_database
let db_name = params[0].get_string().unwrap_or(String::new());
Box::new(client.drop_database(&db_name))
},
3 => { // database_exists
let db_name = params[0].get_string().unwrap_or(String::new());
Box::new(client.database_exists(&db_name))
},
4 => { // list_collections
let db_name = params[0].get_string().unwrap_or(String::new());
Box::new(client.list_collections(&db_name))
},
5 => { // create_collection
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
Box::new(client.create_collection(&db_name, &collection_name))
},
6 => { // drop_collection
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
Box::new(client.drop_collection(&db_name, &collection_name))
},
7 => { // collection_exists
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
Box::new(client.collection_exists(&db_name, &collection_name))
},
8 => { // insert_data
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let data = params[2].get_string().unwrap_or(String::new());
Box::new(client.insert_data(&db_name, &collection_name, &data))
},
1 => {
9 => { // insert_many
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name= params[1].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let data = params[2].get_string().unwrap_or(String::new());
Box::new(client.insert_many(&db_name, &collection_name, &data))
},
10 => { // update_data
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
let update = params[3].get_string().unwrap_or(String::new());
Box::new(client.update_data(&db_name, &collection_name, &query, &update))
},
11 => { // update_many
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
let update = params[3].get_string().unwrap_or(String::new());
Box::new(client.update_many(&db_name, &collection_name, &query, &update))
},
12 => { // delete_data
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
Box::new(client.delete_data(&db_name, &collection_name, &query))
},
13 => { // delete_many
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
Box::new(client.delete_many(&db_name, &collection_name, &query))
},
14 => { // find_data
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
Box::new(client.find_data(&db_name, &collection_name, &query))
},
2 => {
15 => { // find_many
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name= params[1].get_string().unwrap_or(String::new());
Box::new(client.count_documents(&db_name, &collection_name))
},
3 => {
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name= params[1].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
let page = params[3].get_i32().unwrap_or(0);
let page_size = params[4].get_i32().unwrap_or(0) as i32;
Box::new(client.find_many(&db_name, &collection_name, &query, page, page_size))
},
16 => { // find_all
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
let page = params[3].get_i32().unwrap_or(0);
let page_size = params[4].get_i32().unwrap_or(0);
Box::new(client.find_all(&db_name, &collection_name, &query, page, page_size))
},
17 => { // document_exists
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let query = params[2].get_string().unwrap_or(String::new());
Box::new(client.document_exists(&db_name, &collection_name, &query))
},
18 => { // count_documents
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
Box::new(client.count_documents(&db_name, &collection_name))
},
19 => { // run_custom_query
let db_name = params[0].get_string().unwrap_or(String::new());
let query = params[1].get_string().unwrap_or(String::new());
Box::new(client.run_custom_query(&db_name, &query))
},
20 => { // aggregate
let db_name = params[0].get_string().unwrap_or(String::new());
let collection_name = params[1].get_string().unwrap_or(String::new());
let pipeline = params[2].get_string().unwrap_or(String::new());
Box::new(client.aggregate(&db_name, &collection_name, &pipeline))
},
_ => {
Box::new(false)
}
_ => Box::new(false),
}
}

View File

@ -1,379 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "addin1c"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce4a2faf46b8c80fc9f6a9a280bef80b7968d6b5d4324b563e6b8b4717031c3"
dependencies = [
"smallvec",
"utf16_lit",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "cc"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "errno"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "fastrand"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "libc"
version = "0.2.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "native-tls"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "openssl"
version = "0.10.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "opi_tcp"
version = "0.1.0"
dependencies = [
"addin1c",
"native-tls",
]
[[package]]
name = "pkg-config"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustix"
version = "0.38.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "schannel"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.59.0",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "utf16_lit"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -1,17 +0,0 @@
[package]
name = "opi_tcp"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
[dependencies]
addin1c = "0.1"
native-tls = "0.2.12"

View File

@ -1,46 +0,0 @@
mod opi_tcp;
use std::{
ffi::{c_int, c_long, c_void},
sync::atomic::{AtomicI32, Ordering},
};
use opi_tcp::OpiTcp;
use addin1c::{create_component, destroy_component, name, AttachType};
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long {
let addin = OpiTcp::new();
create_component(component, addin)
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
destroy_component(component)
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn GetClassNames() -> *const u16 {
// small strings for performance
name!("Client").as_ptr()
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
3
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn GetAttachType() -> AttachType {
AttachType::Any
}

View File

@ -1,303 +0,0 @@
use addin1c::{name, ParamValue, RawAddin, Tm, Variant};
use std::io::{self, Read, Write};
use std::net::{TcpStream, ToSocketAddrs};
use std::time::Duration;
use native_tls::{TlsConnector, TlsStream};
// Свойства объекта
const PROPS: &[&[u16]] = &[
name!("Адрес"),
name!("Порт"),
name!("SSL")
];
// Объявление методов
const METHODS: &[&[u16]] = &[
name!("ОтправитьСообщение")
];
// Определение типов свойств
pub struct OpiTcp {
address: String,
port: i32,
ssl: bool
}
// Конструктор
impl OpiTcp {
pub fn new() -> OpiTcp {
OpiTcp {
address: String::from(""),
port: 0,
ssl: false
}
}
}
// Обработка удаления объекта
impl Drop for OpiTcp {
fn drop(&mut self) {}
}
// Определение класса
impl RawAddin for OpiTcp {
fn register_extension_as(&mut self) -> &'static [u16] {
name!("Client")
}
fn get_n_props(&mut self) -> usize {
PROPS.len()
}
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
PROPS.iter().position(|&x| x == name)
}
fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> {
PROPS.get(num).copied()
}
// Геттеры
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
match num {
0 => {
let s: Vec<u16> = self.address.encode_utf16().collect();
return val.set_str(s.as_slice());
}
1 => val.set_i32(self.port),
2 => val.set_bool(self.ssl),
_ => return false,
};
true
}
// Сеттеры
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
match num {
0 => match val {
ParamValue::Str(x) => {
self.address = String::from_utf16(x).unwrap();
true
}
_ => false,
},
1 => match val {
ParamValue::I32(x) => {
self.port = *x;
true
}
_ => false,
},
2 => match val {
ParamValue::Bool(x) =>{
self.ssl = *x;
true
}
_ => false,
}
_ => false,
}
}
fn is_prop_readable(&mut self, _num: usize) -> bool {
true
}
fn is_prop_writable(&mut self, num: usize) -> bool {
match num {
0 => true,
1 => true,
2 => true,
_ => false,
}
}
fn get_n_methods(&mut self) -> usize {
METHODS.len()
}
fn find_method(&mut self, name: &[u16]) -> Option<usize> {
METHODS.iter().position(|&x| x == name)
}
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> {
METHODS.get(num).copied()
}
fn get_n_params(&mut self, num: usize) -> usize {
match num {
0 => 2,
_ => 0,
}
}
fn get_param_def_value(
&mut self,
_method_num: usize,
_param_num: usize,
_value: Variant,
) -> bool {
true
}
fn has_ret_val(&mut self, num: usize) -> bool {
match num {
0 => true,
_ => false,
}
}
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool {
false
}
fn call_as_func(
&mut self,
num: usize,
params: &mut [Variant],
ret_value: &mut Variant,
) -> bool {
match num {
0 => {
// Проверяем, является ли первый параметр строкой или бинарными данными
let message: Vec<u8> = match params.get(0).map(|p| p.get()) {
Some(ParamValue::Str(str_message)) => {
// Преобразуем строку из &[u16] в Vec<u8>
String::from_utf16(str_message)
.unwrap_or_default()
.into_bytes()
},
Some(ParamValue::Blob(blob_message)) => {
// Просто передаем бинарные данные
blob_message.to_vec()
},
_ => return false, // Неверный тип данных
};
// Извлекаем таймаут из второго параметра
let ParamValue::I32(timeout) = params.get(1).map(|p| p.get()).unwrap_or(ParamValue::I32(0)) else {
return false; // Неверный тип для таймаута
};
// Вызываем send_message с address, port, извлечённым message и timeout
send_message(&self.address, self.port, &message, timeout as u64, self.ssl, ret_value)
},
_ => false,
}
}
}
fn to_utf16(input: &str) -> Vec<u16> {
input.encode_utf16().collect()
}
pub fn send_message(
address: &str,
port: i32,
message: &dyn AsRef<[u8]>,
timeout_secs: u64,
use_ssl: bool,
ret_value: &mut Variant,
) -> bool {
let addr = format!("{}:{}", address, port);
// Устанавливаем таймаут
let timeout = Duration::from_secs(timeout_secs);
// Создаем TCP соединение
let stream = TcpStream::connect_timeout(&addr.to_socket_addrs().unwrap().next().unwrap(), timeout);
let stream = match stream {
Ok(s) => s,
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to connect: {}", e)));
return true;
}
};
// Применяем таймауты к потокам чтения и записи
if let Err(e) = stream.set_read_timeout(Some(timeout)) {
ret_value.set_str(&to_utf16(&format!("Failed to set read timeout: {}", e)));
return true;
}
if let Err(e) = stream.set_write_timeout(Some(timeout)) {
ret_value.set_str(&to_utf16(&format!("Failed to set write timeout: {}", e)));
return true;
}
// Обрабатываем SSL при необходимости
let mut stream = if use_ssl {
let connector = match TlsConnector::new() {
Ok(c) => c,
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to create TLS connector: {}", e)));
return true;
}
};
match connector.connect(address, stream) {
Ok(s) => StreamWrapper::Secure(s),
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to establish SSL connection: {}", e)));
return true;
}
}
} else {
StreamWrapper::Plain(stream)
};
// Отправляем сообщение
if let Err(e) = stream.write_all(message.as_ref()) {
ret_value.set_str(&to_utf16(&format!("Failed to send message: {}", e)));
return true;
}
// Читаем ответ
let mut response = Vec::new();
match stream.read_to_end(&mut response) {
Ok(_) => {
match String::from_utf8(response) {
Ok(s) => {
let _ = ret_value.set_str(&to_utf16(&s));
}
Err(e) => {
let _ = ret_value.set_str(&to_utf16(&format!("Failed to decode response: {}", e)));
}
}
true
}
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to read response: {}", e)));
true
}
}
}
enum StreamWrapper {
Plain(TcpStream),
Secure(TlsStream<TcpStream>),
}
impl Read for StreamWrapper {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
StreamWrapper::Plain(stream) => stream.read(buf),
StreamWrapper::Secure(stream) => stream.read(buf),
}
}
}
impl Write for StreamWrapper {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
StreamWrapper::Plain(stream) => stream.write(buf),
StreamWrapper::Secure(stream) => stream.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
StreamWrapper::Plain(stream) => stream.flush(),
StreamWrapper::Secure(stream) => stream.flush(),
}
}
}

View File

@ -0,0 +1,2 @@
cargo build --release --target x86_64-pc-windows-msvc
cargo build --release --target x86_64-unknown-linux-gnu