mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 13:01:12 +03:00
Limitations management and real-time MOTD update added.
- deleted unnecessary comments - korewaChino artefacts removed
This commit is contained in:
parent
c53c10cb0a
commit
cfea3e6e71
12 changed files with 79 additions and 84 deletions
4
.github/workflows/docker.yml
vendored
4
.github/workflows/docker.yml
vendored
|
|
@ -3,8 +3,8 @@ name: Create and publish a Docker image
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
tags:
|
||||||
- master
|
- v*.*.*
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
|
|
||||||
8
CREDITS
8
CREDITS
|
|
@ -1 +1,7 @@
|
||||||
Many thanks to PoolloverNathan (https://github.com/PoolloverNathan) and Martinz64 (https://github.com/Martinz64) for their work on which Sculptor was developed.
|
Many thanks to:
|
||||||
|
PoolloverNathan (https://github.com/PoolloverNathan)
|
||||||
|
Martinz64 (https://github.com/Martinz64)
|
||||||
|
for their work on which Sculptor was developed.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
korewaChino (https://github.com/korewaChino)
|
||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1134,7 +1134,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sculptor"
|
name = "sculptor"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"anyhow-http",
|
"anyhow-http",
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ motd = """
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[limitations]
|
||||||
|
maxAvatarSize = 100000
|
||||||
|
maxAvatars = 10
|
||||||
|
|
||||||
# Shiroyashik
|
# Shiroyashik
|
||||||
[advancedUsers.66004548-4de5-49de-bade-9c3933d8eb97]
|
[advancedUsers.66004548-4de5-49de-bade-9c3933d8eb97]
|
||||||
special = [0,0,0,1,0,0] # 6
|
special = [0,0,0,1,0,0] # 6
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -6,8 +6,6 @@ Implements Ping transmission functionality via Websocket and full avatar upload
|
||||||
|
|
||||||
And also a distinctive feature is the possibility of player identification through the third-party authorization system [Ely.By](https://ely.by/)
|
And also a distinctive feature is the possibility of player identification through the third-party authorization system [Ely.By](https://ely.by/)
|
||||||
|
|
||||||
> This is a personal fork of Sculptor, made to be a workaround for a private server.
|
|
||||||
|
|
||||||
### Running with Docker
|
### Running with Docker
|
||||||
|
|
||||||
You will need an already configured Docker with Traefik (you can use any reverse proxy)
|
You will need an already configured Docker with Traefik (you can use any reverse proxy)
|
||||||
|
|
@ -28,8 +26,13 @@ To do this, you will need to reverse proxy port 6665 to your domain with SSL
|
||||||
3. Set up your reverse proxy server
|
3. Set up your reverse proxy server
|
||||||
4. `cargo run`
|
4. `cargo run`
|
||||||
|
|
||||||
### TODO:
|
### Public server
|
||||||
- [ ] Realization of storing profiles in the database
|
|
||||||
- [ ] Frontend for moderation
|
I'm keeping the public server running at the moment!
|
||||||
- [ ] Autonomous working without reverse proxy server
|
You can use it if running your own Sculptor instance is difficult for you.
|
||||||
- [ ] and many other...
|
|
||||||
|
> figura.shsr.ru
|
||||||
|
|
||||||
|
For reasons beyond my control, the server is not available in some countries.
|
||||||
|
|
||||||
|
[Check server availability](https://figura.shsr.ru/health)
|
||||||
|
|
@ -2,17 +2,22 @@ name: sculptor
|
||||||
|
|
||||||
services:
|
services:
|
||||||
sculptor:
|
sculptor:
|
||||||
build: .
|
# build: .
|
||||||
image: ghcr.io/korewachino/sculptor:latest
|
image: ghcr.io/shiroyashik/sculptor:latest
|
||||||
container_name: sculptor
|
container_name: sculptor
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./Config.toml:/app/Config.toml:ro
|
- ./Config.toml:/app/Config.toml:ro
|
||||||
- ./avatars:/app/avatars
|
- ./avatars:/app/avatars
|
||||||
## Recommended for use with reverse proxy.
|
## Recommended for use with reverse proxy.
|
||||||
|
# networks:
|
||||||
|
# - traefik
|
||||||
# labels:
|
# labels:
|
||||||
# - traefik.enable=true
|
# - traefik.enable=true
|
||||||
# - traefik.http.routers.sculptor.rule=Host(`mc.example.com`)
|
# - traefik.http.routers.sculptor.rule=Host(`mc.example.com`)
|
||||||
# - traefik.http.routers.sculptor.entrypoints=websecure, web
|
# - traefik.http.routers.sculptor.entrypoints=websecure, web
|
||||||
# - traefik.http.routers.sculptor.tls=true
|
# - traefik.http.routers.sculptor.tls=true
|
||||||
# - traefik.http.routers.sculptor.tls.certresolver=production
|
# - traefik.http.routers.sculptor.tls.certresolver=production
|
||||||
|
# networks:
|
||||||
|
# traefik:
|
||||||
|
# external: true
|
||||||
|
|
|
||||||
38
src/auth.rs
38
src/auth.rs
|
|
@ -56,7 +56,6 @@ async fn verify(
|
||||||
if let Some((uuid, auth_system)) = has_joined(&server_id, &username).await.unwrap() {
|
if let Some((uuid, auth_system)) = has_joined(&server_id, &username).await.unwrap() {
|
||||||
info!("[Authorization] {username} logged in using {auth_system:?}");
|
info!("[Authorization] {username} logged in using {auth_system:?}");
|
||||||
let authenticated = state.authenticated;
|
let authenticated = state.authenticated;
|
||||||
// let link = state.authenticated_link.lock().await; // // Реализация поиска пользователя в HashMap по UUID
|
|
||||||
authenticated.insert(
|
authenticated.insert(
|
||||||
uuid,
|
uuid,
|
||||||
server_id.clone(),
|
server_id.clone(),
|
||||||
|
|
@ -66,7 +65,6 @@ async fn verify(
|
||||||
auth_system,
|
auth_system,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// link.insert(uuid, crate::AuthenticatedLink(server_id.clone())); // Реализация поиска пользователя в HashMap по UUID
|
|
||||||
server_id.to_string()
|
server_id.to_string()
|
||||||
} else {
|
} else {
|
||||||
String::from("failed to verify")
|
String::from("failed to verify")
|
||||||
|
|
@ -135,7 +133,6 @@ impl ToString for AuthSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get UUID from JSON response
|
/// Get UUID from JSON response
|
||||||
// Written to be reusable so we don't have to specify the same complex code twice
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_id_json(json: &serde_json::Value) -> anyhow::Result<Uuid> {
|
fn get_id_json(json: &serde_json::Value) -> anyhow::Result<Uuid> {
|
||||||
trace!("json: {json:#?}"); // For debugging, we'll get to this later!
|
trace!("json: {json:#?}"); // For debugging, we'll get to this later!
|
||||||
|
|
@ -143,8 +140,6 @@ fn get_id_json(json: &serde_json::Value) -> anyhow::Result<Uuid> {
|
||||||
Ok(uuid)
|
Ok(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Considering dropping ely.by support here, I don't really want to deal with it
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn fetch_json(
|
async fn fetch_json(
|
||||||
url: &str,
|
url: &str,
|
||||||
|
|
@ -181,39 +176,6 @@ pub async fn has_joined(
|
||||||
server_id: &str,
|
server_id: &str,
|
||||||
username: &str,
|
username: &str,
|
||||||
) -> anyhow::Result<Option<(Uuid, AuthSystem)>> {
|
) -> anyhow::Result<Option<(Uuid, AuthSystem)>> {
|
||||||
// let client = reqwest::Client::new();
|
|
||||||
// tokio::select! {
|
|
||||||
// Ok(Some(res)) = async {
|
|
||||||
// let res = client.clone().get(
|
|
||||||
// format!("http://minecraft.ely.by/session/hasJoined?serverId={server_id}&username={username}")).send().await?;
|
|
||||||
// debug!("{res:?}");
|
|
||||||
// match res.status().as_u16() {
|
|
||||||
// 200 => {
|
|
||||||
// let json = serde_json::from_str::<serde_json::Value>(&res.text().await?)?;
|
|
||||||
// let uuid = get_id_json(&json)?;
|
|
||||||
// Ok(Some((uuid, AuthSystem::ElyBy)))
|
|
||||||
// },
|
|
||||||
// 401 => Ok(None),
|
|
||||||
// _ => Err(anyhow::anyhow!("Unknown code: {}", res.status().as_u16()))
|
|
||||||
// }
|
|
||||||
// } => {Ok(Some(res))}
|
|
||||||
// Ok(Some(res)) = async {
|
|
||||||
// let res = client.clone().get(
|
|
||||||
// format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?serverId={server_id}&username={username}")).send().await?;
|
|
||||||
// debug!("{res:?}");
|
|
||||||
// match res.status().as_u16() {
|
|
||||||
// 200 => {
|
|
||||||
// let json = serde_json::from_str::<serde_json::Value>(&res.text().await?)?;
|
|
||||||
// let uuid = get_id_json(&json)?;
|
|
||||||
// Ok(Some((uuid, AuthSystem::Mojang)))
|
|
||||||
// },
|
|
||||||
// 204 => Ok(None),
|
|
||||||
// _ => Err(anyhow::anyhow!("Unknown code: {}", res.status().as_u16()))
|
|
||||||
// }
|
|
||||||
// } => {Ok(Some(res))}
|
|
||||||
// else => {Err(anyhow!("Something went wrong in external apis request process"))}
|
|
||||||
// }
|
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Ok(Some(res)) = fetch_json("http://minecraft.ely.by/session/hasJoined", server_id, username) => {Ok(Some(res))},
|
Ok(Some(res)) = fetch_json("http://minecraft.ely.by/session/hasJoined", server_id, username) => {Ok(Some(res))},
|
||||||
Ok(Some(res)) = fetch_json("https://sessionserver.mojang.com/session/minecraft/hasJoined", server_id, username) => {Ok(Some(res))},
|
Ok(Some(res)) = fetch_json("https://sessionserver.mojang.com/session/minecraft/hasJoined", server_id, username) => {Ok(Some(res))},
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,22 @@ use std::{io::Read, path::PathBuf};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub listen: String,
|
pub listen: String,
|
||||||
pub motd: String,
|
pub motd: String,
|
||||||
|
pub limitations: Limitations,
|
||||||
pub advanced_users: Table,
|
pub advanced_users: Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Limitations {
|
||||||
|
pub max_avatar_size: u64,
|
||||||
|
pub max_avatars: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn parse(path: PathBuf) -> Self {
|
pub fn parse(path: PathBuf) -> Self {
|
||||||
let mut file = std::fs::File::open(path).expect("Access denied or file doesn't exists!");
|
let mut file = std::fs::File::open(path).expect("Access denied or file doesn't exists!");
|
||||||
|
|
|
||||||
21
src/info.rs
21
src/info.rs
|
|
@ -1,6 +1,14 @@
|
||||||
use axum::Json;
|
use axum::{extract::State, Json};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
use crate::AppState;
|
||||||
|
|
||||||
|
/// Assert health of the server
|
||||||
|
/// If times out, the server is considered dead, so we can return basically anything
|
||||||
|
pub async fn health_check() -> String {
|
||||||
|
"ok".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn version() -> Json<Value> {
|
pub async fn version() -> Json<Value> {
|
||||||
Json(json!({
|
Json(json!({
|
||||||
"release": "0.1.4",
|
"release": "0.1.4",
|
||||||
|
|
@ -8,7 +16,12 @@ pub async fn version() -> Json<Value> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn limits() -> Json<Value> {
|
pub async fn motd(State(state): State<AppState>) -> String {
|
||||||
|
state.config.lock().await.motd.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn limits(State(state): State<AppState>) -> Json<Value> {
|
||||||
|
let state = &state.config.lock().await.limitations;
|
||||||
Json(json!({
|
Json(json!({
|
||||||
"rate": {
|
"rate": {
|
||||||
"pingSize": 1024,
|
"pingSize": 1024,
|
||||||
|
|
@ -18,8 +31,8 @@ pub async fn limits() -> Json<Value> {
|
||||||
"upload": 1
|
"upload": 1
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
"maxAvatarSize": 100000,
|
"maxAvatarSize": state.max_avatar_size,
|
||||||
"maxAvatars": 10,
|
"maxAvatars": state.max_avatars,
|
||||||
"allowedBadges": {
|
"allowedBadges": {
|
||||||
"special": [0,0,0,0,0,0],
|
"special": [0,0,0,0,0,0],
|
||||||
"pride": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
"pride": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
||||||
|
|
|
||||||
37
src/main.rs
37
src/main.rs
|
|
@ -90,18 +90,10 @@ pub struct AppState {
|
||||||
authenticated: Arc<Authenticated>, // <SHA1 serverId, Userinfo> NOTE: In the future, try it in a separate LockRw branch
|
authenticated: Arc<Authenticated>, // <SHA1 serverId, Userinfo> NOTE: In the future, try it in a separate LockRw branch
|
||||||
// Ping broadcasts for WebSocket connections
|
// Ping broadcasts for WebSocket connections
|
||||||
broadcasts: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
|
broadcasts: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
|
||||||
// Advanced configured users
|
// Current configuration
|
||||||
advanced_users: Arc<Mutex<toml::Table>>,
|
config: Arc<Mutex<config::Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert health of the server
|
|
||||||
/// If times out, the server is considered dead, so we can return basically anything
|
|
||||||
async fn health_check() -> String {
|
|
||||||
// tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
|
||||||
"ok".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const LOGGER_ENV: &str = "RUST_LOG";
|
const LOGGER_ENV: &str = "RUST_LOG";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
@ -118,29 +110,30 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let config_file = std::env::var("CONFIG_PATH").unwrap_or_else(|_| "Config.toml".into());
|
let config_file = std::env::var("CONFIG_PATH").unwrap_or_else(|_| "Config.toml".into());
|
||||||
|
|
||||||
info!("The Sculptor MMSI edition v{}", env!("CARGO_PKG_VERSION"));
|
info!("The Sculptor v{}", env!("CARGO_PKG_VERSION"));
|
||||||
// Config
|
// Config
|
||||||
let config = config::Config::parse(config_file.clone().into());
|
let config = Arc::new(Mutex::new(config::Config::parse(config_file.clone().into())));
|
||||||
let listen = config.listen.as_str();
|
let listen = config.lock().await.listen.clone();
|
||||||
|
|
||||||
// State
|
// State
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
pending: Arc::new(DashMap::new()),
|
pending: Arc::new(DashMap::new()),
|
||||||
authenticated: Arc::new(Authenticated::new()),
|
authenticated: Arc::new(Authenticated::new()),
|
||||||
broadcasts: Arc::new(DashMap::new()),
|
broadcasts: Arc::new(DashMap::new()),
|
||||||
advanced_users: Arc::new(Mutex::new(config.advanced_users)),
|
config: config,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Automatic update of advanced_users while the server is running
|
// Automatic update of configuration while the server is running
|
||||||
let advanced_users = state.advanced_users.clone();
|
let config_update = state.config.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
||||||
|
|
||||||
let new_config = config::Config::parse(config_file.clone().into()).advanced_users;
|
let new_config = config::Config::parse(config_file.clone().into());
|
||||||
let mut config = advanced_users.lock().await;
|
let mut config = config_update.lock().await;
|
||||||
|
|
||||||
if new_config != *config {
|
if new_config != *config {
|
||||||
|
info!("Server configuration modification detected!");
|
||||||
*config = new_config;
|
*config = new_config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,20 +141,20 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let api = Router::new()
|
let api = Router::new()
|
||||||
.nest("//auth", api_auth::router())
|
.nest("//auth", api_auth::router())
|
||||||
.route("/limits", get(api_info::limits)) // TODO:
|
.route("/limits", get(api_info::limits))
|
||||||
.route("/version", get(api_info::version))
|
.route("/version", get(api_info::version))
|
||||||
.route("/motd", get(|| async { config.motd }))
|
.route("/motd", get(api_info::motd))
|
||||||
.route("/equip", post(api_profile::equip_avatar))
|
.route("/equip", post(api_profile::equip_avatar))
|
||||||
.route("/:uuid", get(api_profile::user_info))
|
.route("/:uuid", get(api_profile::user_info))
|
||||||
.route("/:uuid/avatar", get(api_profile::download_avatar))
|
.route("/:uuid/avatar", get(api_profile::download_avatar))
|
||||||
.route("/avatar", put(api_profile::upload_avatar))
|
.route("/avatar", put(api_profile::upload_avatar))
|
||||||
.route("/avatar", delete(api_profile::delete_avatar)); // delete Avatar
|
.route("/avatar", delete(api_profile::delete_avatar));
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.nest("/api", api)
|
.nest("/api", api)
|
||||||
.route("/api/", get(api_auth::status))
|
.route("/api/", get(api_auth::status))
|
||||||
.route("/ws", get(handler))
|
.route("/ws", get(handler))
|
||||||
.route("/health", get(health_check))
|
.route("/health", get(api_info::health_check))
|
||||||
.route_layer(from_extractor::<api_auth::Token>())
|
.route_layer(from_extractor::<api_auth::Token>())
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
.layer(TraceLayer::new_for_http().on_request(()));
|
.layer(TraceLayer::new_for_http().on_request(()));
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use crate::{
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn user_info(
|
pub async fn user_info(
|
||||||
Path(uuid): Path<Uuid>,
|
Path(uuid): Path<Uuid>,
|
||||||
State(state): State<AppState>, // FIXME: Variable doesn't using!
|
State(state): State<AppState>,
|
||||||
) -> Json<Value> {
|
) -> Json<Value> {
|
||||||
tracing::info!("Receiving profile information for {}", uuid);
|
tracing::info!("Receiving profile information for {}", uuid);
|
||||||
|
|
||||||
|
|
@ -47,10 +47,10 @@ pub async fn user_info(
|
||||||
},
|
},
|
||||||
"version": "0.1.4+1.20.1",
|
"version": "0.1.4+1.20.1",
|
||||||
"banned": false,
|
"banned": false,
|
||||||
"authSystem": auth_system // add Trust
|
"authSystem": auth_system
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(settings) = state.advanced_users.lock().await.get(&formatted_uuid) {
|
if let Some(settings) = state.config.lock().await.advanced_users.get(&formatted_uuid) {
|
||||||
let pride = get_correct_array(settings.get("pride").unwrap());
|
let pride = get_correct_array(settings.get("pride").unwrap());
|
||||||
let special = get_correct_array(settings.get("special").unwrap());
|
let special = get_correct_array(settings.get("special").unwrap());
|
||||||
let badges = user_info_response
|
let badges = user_info_response
|
||||||
|
|
@ -141,7 +141,7 @@ pub async fn equip_avatar(Token(token): Token, State(state): State<AppState>) ->
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
warn!("[WebSocket] Failed to send Event! Maybe there is no one to send")
|
warn!("[WebSocket] Failed to send Event! Maybe there is no one to send")
|
||||||
// FIXME: Засунуть в Handler
|
// TODO: Put into Handler
|
||||||
};
|
};
|
||||||
"ok".to_string()
|
"ok".to_string()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||||
use ring::digest::{self, digest};
|
use ring::digest::{self, digest};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
// Кор функции
|
// Core functions
|
||||||
pub fn rand() -> [u8; 50] {
|
pub fn rand() -> [u8; 50] {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let distr = rand::distributions::Uniform::new_inclusive(0, 255);
|
let distr = rand::distributions::Uniform::new_inclusive(0, 255);
|
||||||
|
|
@ -15,6 +15,7 @@ pub fn rand() -> [u8; 50] {
|
||||||
}
|
}
|
||||||
nums
|
nums
|
||||||
}
|
}
|
||||||
|
|
||||||
//? What is this guy doing
|
//? What is this guy doing
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn bytes_into_string(code: &[u8]) -> String {
|
pub fn bytes_into_string(code: &[u8]) -> String {
|
||||||
|
|
@ -27,7 +28,7 @@ pub fn bytes_into_string(code: &[u8]) -> String {
|
||||||
|
|
||||||
// String::from_utf8_lossy(code).to_string() // Tried this, causes corrupted string
|
// String::from_utf8_lossy(code).to_string() // Tried this, causes corrupted string
|
||||||
}
|
}
|
||||||
// Конец кор функций
|
// End of Core functions
|
||||||
|
|
||||||
pub fn _generate_hex_string(length: usize) -> String {
|
pub fn _generate_hex_string(length: usize) -> String {
|
||||||
// FIXME: Variable doesn't using!
|
// FIXME: Variable doesn't using!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue