Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Dunitrust
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
nodes
rust
Dunitrust
Commits
9b098712
Commit
9b098712
authored
7 years ago
by
Éloïs
Browse files
Options
Downloads
Patches
Plain Diff
[enh]
#68
add core crate
parent
ceaa5970
Branches
Branches containing commit
Tags
Tags containing commit
1 merge request
!58
Resolve "Add crates blockchain, conf, core, dal, message, module, network, tui and ws2p"
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
core/Cargo.toml
+28
-0
28 additions, 0 deletions
core/Cargo.toml
core/cli/en.yml
+64
-0
64 additions, 0 deletions
core/cli/en.yml
core/lib.rs
+440
-0
440 additions, 0 deletions
core/lib.rs
with
532 additions
and
0 deletions
core/Cargo.toml
0 → 100644
+
28
−
0
View file @
9b098712
[package]
name
=
"duniter-core"
version
=
"0.1.0"
authors
=
[
"librelois <elois@ifee.fr>"
]
description
=
"Duniter-rs core."
license
=
"AGPL-3.0"
[lib]
path
=
"lib.rs"
[dependencies]
clap
=
{
version
=
"2.31.2"
,
features
=
[
"yaml"
]}
duniter-blockchain
=
{
path
=
"../blockchain"
}
duniter-conf
=
{
path
=
"../conf"
}
duniter-crypto
=
{
path
=
"../crypto"
}
duniter-message
=
{
path
=
"../message"
}
duniter-module
=
{
path
=
"../module"
}
lazy_static
=
"1.0.0"
log
=
"0.4.1"
rand
=
"0.4.2"
regex
=
"0.2.6"
rust-crypto
=
"0.2.36"
serde
=
"1.0.24"
serde_derive
=
"1.0.24"
serde_json
=
"1.0.9"
simplelog
=
"0.5.1"
sqlite
=
"0.23.9"
threadpool
=
"1.7.1"
\ No newline at end of file
This diff is collapsed.
Click to expand it.
core/cli/en.yml
0 → 100644
+
64
−
0
View file @
9b098712
name
:
durs
version
:
"
0.1.0"
author
:
Elois L. <elois@duniter.org>
about
:
Rust implementation of Duniter
args
:
-
profile
:
short
:
p
long
:
profile
value_name
:
CUSTOM_PROFILE
help
:
Set a custom datas folder
takes_value
:
true
-
logs
:
short
:
l
long
:
logs
value_name
:
LOGS_LEVEL
takes_value
:
true
possible_values
:
[
"
e"
,
"
w"
,
"
i"
,
"
d"
,
"
t"
,
"
error"
,
"
warn"
,
"
info"
,
"
debug"
,
"
trace"
]
help
:
Set the level of logs verbosity
long_help
:
"
Set
the
level
of
logs
verbosity
:
\n
error
:
print
serious
errors
\n
warn
:
print
hazardous
situations
\n
info
:
default
level
\n
debug
:
print
a
lot
of
debug
informations
\n
trace
:
print
all
traces
(highly
verbose)"
subcommands
:
-
start
:
about
:
start duniter server
version
:
"
0.1.0"
author
:
Elois L. <elois@duniter.org>
-
sync_ts
:
about
:
synchronization via a duniter-ts database
version
:
"
0.1.0"
author
:
Elois L. <elois@duniter.org>
args
:
-
TS_PROFILE
:
help
:
Set the ts profile to use
index
:
1
-
cautious
:
short
:
c
long
:
cautious
help
:
cautious mode (check all protocol rules, very slow)
-
msync_ts
:
about
:
synchronization in memory mode via a duniter-ts database
version
:
"
0.1.0"
author
:
Elois L. <elois@duniter.org>
args
:
-
TS_PROFILE
:
help
:
Set the ts profile to use
index
:
1
-
cautious
:
short
:
c
long
:
cautious
help
:
cautious mode (check all protocol rules, very slow)
-
reset
:
about
:
reset data or conf or all
version
:
"
0.1.0"
author
:
Elois L. <elois@duniter.org>
args
:
-
DATAS_TYPE
:
help
:
choose type datas to reset
index
:
1
possible_values
:
[
"
data"
,
"
conf"
,
"
all"
]
required
:
true
\ No newline at end of file
This diff is collapsed.
Click to expand it.
core/lib.rs
0 → 100644
+
440
−
0
View file @
9b098712
// Copyright (C) 2018 The Duniter Project Developers.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Crate containing Duniter-rust core.
#![cfg_attr(feature
=
"strict"
,
deny(warnings))]
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
#[macro_use]
extern
crate
clap
;
#[macro_use]
extern
crate
log
;
extern
crate
duniter_blockchain
;
extern
crate
duniter_conf
;
extern
crate
duniter_crypto
;
extern
crate
duniter_message
;
extern
crate
duniter_module
;
extern
crate
serde_json
;
extern
crate
simplelog
;
extern
crate
sqlite
;
extern
crate
threadpool
;
use
self
::
threadpool
::
ThreadPool
;
use
clap
::{
App
,
ArgMatches
};
use
duniter_blockchain
::
BlockchainModule
;
use
duniter_conf
::
DuniterKeyPairs
;
use
duniter_crypto
::
keys
::
ed25519
;
use
duniter_message
::
DuniterMessage
;
use
duniter_module
::
*
;
use
log
::
Level
;
use
simplelog
::
*
;
use
std
::
env
;
use
std
::
fs
;
use
std
::
fs
::{
File
,
OpenOptions
};
use
std
::
sync
::
mpsc
;
use
std
::
thread
;
use
std
::
time
::
Duration
;
#[derive(Debug)]
/// Duniter Core Datas
pub
struct
DuniterCore
{
/// Does the entered command require to launch server ?
pub
start
:
bool
,
/// Software name
pub
soft_name
:
&
'static
str
,
/// Soft version
pub
soft_version
:
&
'static
str
,
/// Keypairs
pub
keypairs
:
DuniterKeyPairs
,
/// Duniter configuration
pub
conf
:
DuniterConf
,
/// Run duration. Zero = infinite duration.
pub
run_duration_in_secs
:
u64
,
/// Sender channel of rooter thread
pub
rooter_sender
:
mpsc
::
Sender
<
RooterThreadMessage
<
DuniterMessage
>>
,
/// Count the number of plugged modules
pub
modules_count
:
usize
,
/// ThreadPool that execute plugged modules
pub
thread_pool
:
ThreadPool
,
}
impl
DuniterCore
{
/// Instantiate Duniter classic node
pub
fn
new
(
soft_name
:
&
'static
str
,
soft_version
:
&
'static
str
)
->
Option
<
DuniterCore
>
{
DuniterCore
::
new_specialized_node
(
soft_name
,
soft_version
,
0
,
vec!
[],
vec!
[],
None
)
}
/// Instantiate Duniter specialize node
pub
fn
new_specialized_node
<
'a
,
'b
>
(
soft_name
:
&
'static
str
,
soft_version
:
&
'static
str
,
run_duration_in_secs
:
u64
,
external_followers
:
Vec
<
mpsc
::
Sender
<
DuniterMessage
>>
,
sup_apps
:
Vec
<
App
<
'a
,
'b
>>
,
sup_apps_fn
:
Option
<&
Fn
(
&
str
,
&
ArgMatches
)
->
()
>
,
)
->
Option
<
DuniterCore
>
{
// Get cli conf
let
yaml
=
load_yaml!
(
"./cli/en.yml"
);
let
cli_conf
=
App
::
from_yaml
(
yaml
);
// Math command line arguments
let
cli_args
=
if
!
sup_apps
.is_empty
()
{
cli_conf
.subcommands
(
sup_apps
)
.get_matches
()
}
else
{
cli_conf
.get_matches
()
};
// Get datas profile name
let
profile
=
match_profile
(
&
cli_args
);
// Init logger
init_logger
(
profile
.as_str
(),
soft_name
,
&
cli_args
);
// Load global conf
let
(
conf
,
keypairs
)
=
duniter_conf
::
load_conf
(
profile
.as_str
());
info!
(
"Success to load global conf."
);
if
let
Some
(
_matches
)
=
cli_args
.subcommand_matches
(
"start"
)
{
Some
(
start
(
soft_name
,
soft_version
,
keypairs
,
conf
,
run_duration_in_secs
,
external_followers
,
))
}
else
if
let
Some
(
matches
)
=
cli_args
.subcommand_matches
(
"sync_ts"
)
{
let
ts_profile
=
matches
.value_of
(
"TS_PROFILE"
)
.unwrap_or
(
"duniter_default"
);
sync_ts
(
conf
,
ts_profile
,
matches
.is_present
(
"cautious"
));
None
}
else
if
let
Some
(
matches
)
=
cli_args
.subcommand_matches
(
"reset"
)
{
let
mut
profile_path
=
match
env
::
home_dir
()
{
Some
(
path
)
=>
path
,
None
=>
panic!
(
"Impossible to get your home dir !"
),
};
profile_path
.push
(
".config"
);
profile_path
.push
(
duniter_conf
::
get_user_datas_folder
());
profile_path
.push
(
profile
.clone
());
if
!
profile_path
.as_path
()
.exists
()
{
panic!
(
format!
(
"Error : {} profile don't exist !"
,
profile
));
}
match
matches
.value_of
(
"DATAS_TYPE"
)
.unwrap
()
{
"data"
=>
{
let
mut
currency_datas_path
=
profile_path
.clone
();
currency_datas_path
.push
(
"g1"
);
fs
::
remove_dir_all
(
currency_datas_path
.as_path
())
.expect
(
"Fail to remove all currency datas !"
);
}
"conf"
=>
{
let
mut
conf_file_path
=
profile_path
.clone
();
conf_file_path
.push
(
"conf.json"
);
fs
::
remove_file
(
conf_file_path
.as_path
())
.expect
(
"Fail to remove conf file !"
);
let
mut
conf_keys_path
=
profile_path
.clone
();
conf_keys_path
.push
(
"keypairs.json"
);
fs
::
remove_file
(
conf_keys_path
.as_path
())
.expect
(
"Fail to remove keypairs file !"
);
}
"all"
=>
{
fs
::
remove_dir_all
(
profile_path
.as_path
())
.expect
(
"Fail to remove all profile datas !"
);
}
_
=>
{}
}
None
}
else
if
let
Some
(
sup_apps_fn
)
=
sup_apps_fn
{
sup_apps_fn
(
profile
.as_str
(),
&
cli_args
);
None
}
else
{
panic!
(
"unknow sub-command !"
)
}
}
/// Start blockchain module
pub
fn
start_blockchain
(
&
self
)
{
if
self
.start
{
thread
::
sleep
(
Duration
::
from_secs
(
2
));
// Create blockchain module channel
let
(
blockchain_sender
,
blockchain_receiver
):
(
mpsc
::
Sender
<
DuniterMessage
>
,
mpsc
::
Receiver
<
DuniterMessage
>
,
)
=
mpsc
::
channel
();
// Send blockchain sender to rooter thread
self
.rooter_sender
.send
(
RooterThreadMessage
::
ModuleSender
(
blockchain_sender
))
.expect
(
"Fatal error: fail to send blockchain sender to rooter thread !"
);
// Send modules_count to rooter thread
self
.rooter_sender
.send
(
RooterThreadMessage
::
ModulesCount
(
self
.modules_count
+
1
))
.expect
(
"Fatal error: fail to send modules count to rooter thread !"
);
// Instantiate blockchain module and load is conf
let
mut
blockchain_module
=
BlockchainModule
::
load_blockchain_conf
(
&
self
.conf
,
RequiredKeysContent
::
MemberKeyPair
(
None
),
false
,
);
info!
(
"Success to load Blockchain module."
);
// Start blockchain module in main thread
blockchain_module
.start_blockchain
(
blockchain_receiver
);
}
}
/// Plug a module
pub
fn
plug
<
M
:
DuniterModule
<
ed25519
::
PublicKey
,
ed25519
::
KeyPair
,
DuniterMessage
>>
(
&
mut
self
)
{
if
self
.start
{
// Start module in a new thread
let
soft_name_clone
=
self
.soft_name
.clone
();
let
soft_version_clone
=
self
.soft_version
.clone
();
let
required_keys
=
DuniterKeyPairs
::
get_required_keys_content
(
M
::
ask_required_keys
(),
self
.keypairs
.clone
(),
);
let
module_conf
=
if
let
Some
(
module_conf_
)
=
self
.conf
.clone
()
.modules
()
.get
(
&
M
::
id
()
.to_string
()
.as_str
())
{
module_conf_
.clone
()
}
else
{
M
::
default_conf
()
};
let
rooter_sender_clone
=
self
.rooter_sender
.clone
();
let
conf_clone
=
self
.conf
.clone
();
self
.thread_pool
.execute
(
move
||
{
M
::
start
(
soft_name_clone
,
soft_version_clone
,
required_keys
,
&
conf_clone
,
&
module_conf
,
rooter_sender_clone
,
false
,
)
.expect
(
&
format!
(
"Fatal error : fail to load {} Module !"
,
M
::
id
()
.to_string
()
));
});
self
.modules_count
+=
1
;
info!
(
"Success to load {} module."
,
M
::
id
()
.to_string
());
}
}
}
/// Match cli option --profile
pub
fn
match_profile
(
cli_args
:
&
ArgMatches
)
->
String
{
String
::
from
(
cli_args
.value_of
(
"profile"
)
.unwrap_or
(
"default"
))
}
/// Launch duniter server
pub
fn
start
(
soft_name
:
&
'static
str
,
soft_version
:
&
'static
str
,
keypairs
:
DuniterKeyPairs
,
conf
:
DuniterConf
,
run_duration_in_secs
:
u64
,
external_followers
:
Vec
<
mpsc
::
Sender
<
DuniterMessage
>>
,
)
->
DuniterCore
{
info!
(
"Starting Duniter-rs..."
);
// Create senders channel
let
(
rooter_sender
,
main_receiver
):
(
mpsc
::
Sender
<
RooterThreadMessage
<
DuniterMessage
>>
,
mpsc
::
Receiver
<
RooterThreadMessage
<
DuniterMessage
>>
,
)
=
mpsc
::
channel
();
// Create rooter thread
thread
::
spawn
(
move
||
{
// Wait to receiver modules senders
let
mut
modules_senders
:
Vec
<
mpsc
::
Sender
<
DuniterMessage
>>
=
Vec
::
new
();
let
mut
modules_count_expected
=
None
;
while
modules_count_expected
.is_none
()
||
modules_senders
.len
()
<
modules_count_expected
.unwrap
()
+
1
{
match
main_receiver
.recv_timeout
(
Duration
::
from_secs
(
20
))
{
Ok
(
mess
)
=>
{
match
mess
{
RooterThreadMessage
::
ModuleSender
(
module_sender
)
=>
{
// Subscribe this module to all others modules
for
other_module
in
modules_senders
.clone
()
{
if
other_module
.send
(
DuniterMessage
::
Followers
(
vec!
[
module_sender
.clone
()]))
.is_err
()
{
panic!
(
"Fatal error : fail to send all modules senders to all modules !"
);
}
}
// Subcribe this module to all external_followers
for
external_follower
in
external_followers
.clone
()
{
if
external_follower
.send
(
DuniterMessage
::
Followers
(
vec!
[
module_sender
.clone
()]))
.is_err
()
{
panic!
(
"Fatal error : fail to send all modules senders to all external_followers !"
);
}
}
// Subscribe all other modules to this module
if
module_sender
.send
(
DuniterMessage
::
Followers
(
modules_senders
.clone
()))
.is_err
()
{
panic!
(
"Fatal error : fail to send all modules senders to all modules !"
);
}
// Subcribe all external_followers to this module
if
module_sender
.send
(
DuniterMessage
::
Followers
(
external_followers
.clone
()))
.is_err
()
{
panic!
(
"Fatal error : fail to send all external_followers to all modules !"
);
}
// Push this module to modules_senders list
modules_senders
.push
(
module_sender
);
// Log the number of modules_senders received
info!
(
"Rooter thread receive {} module senders"
,
modules_senders
.len
()
);
}
RooterThreadMessage
::
ModulesCount
(
modules_count
)
=>
{
info!
(
"Rooter thread receive ModulesCount({})"
,
modules_count
);
if
modules_senders
.len
()
==
modules_count
{
break
;
}
else
if
modules_senders
.len
()
<
modules_count
{
modules_count_expected
=
Some
(
modules_count
);
}
else
{
panic!
(
"Fatal error : Receive more modules_sender than expected !"
)
}
}
}
}
Err
(
e
)
=>
match
e
{
mpsc
::
RecvTimeoutError
::
Timeout
=>
{
panic!
(
"Fatal error : not receive all modules_senders after 20 secs !"
)
}
mpsc
::
RecvTimeoutError
::
Disconnected
=>
{
panic!
(
"Fatal error : rooter thread disconnnected !"
)
}
},
}
}
info!
(
"Receive all modules senders."
);
if
run_duration_in_secs
>
0
{
thread
::
sleep
(
Duration
::
from_secs
(
run_duration_in_secs
));
// Send DuniterMessage::Stop() to all modules
for
sender
in
modules_senders
{
if
sender
.send
(
DuniterMessage
::
Stop
())
.is_err
()
{
panic!
(
"Fail to send Stop() message to one module !"
)
}
}
thread
::
sleep
(
Duration
::
from_secs
(
2
));
}
});
// Instanciate DuniterCore
DuniterCore
{
start
:
true
,
soft_name
,
soft_version
,
keypairs
,
conf
,
run_duration_in_secs
,
rooter_sender
,
modules_count
:
0
,
thread_pool
:
ThreadPool
::
new
(
2
),
}
}
/// Launch synchronisation from a duniter-ts database
pub
fn
sync_ts
(
conf
:
DuniterConf
,
ts_profile
:
&
str
,
cautious
:
bool
)
{
// Launch sync-ts
BlockchainModule
::
sync_ts
(
&
conf
,
ts_profile
,
cautious
);
}
/// Initialize logger
pub
fn
init_logger
(
profile
:
&
str
,
soft_name
:
&
'static
str
,
cli_args
:
&
ArgMatches
)
{
// Get datas folder path
let
mut
log_file_path
=
match
env
::
home_dir
()
{
Some
(
path
)
=>
path
,
None
=>
panic!
(
"Fatal error : Impossible to get your home dir!"
),
};
log_file_path
.push
(
".config"
);
if
!
log_file_path
.as_path
()
.exists
()
{
fs
::
create_dir
(
log_file_path
.as_path
())
.expect
(
"Impossible to create ~/.config dir !"
);
}
log_file_path
.push
(
duniter_conf
::
get_user_datas_folder
());
if
!
log_file_path
.as_path
()
.exists
()
{
fs
::
create_dir
(
log_file_path
.as_path
())
.expect
(
"Impossible to create ~/.config/durs dir !"
);
}
log_file_path
.push
(
profile
);
// Create datas folder if not exist
if
!
log_file_path
.as_path
()
.exists
()
{
fs
::
create_dir
(
log_file_path
.as_path
())
.expect
(
"Impossible to create your profile dir !"
);
}
// Get log_file_path
log_file_path
.push
(
format!
(
"{}.log"
,
soft_name
));
// Get log level
let
log_level
=
match
cli_args
.value_of
(
"logs"
)
.unwrap_or
(
"i"
)
{
"e"
|
"error"
=>
Level
::
Error
,
"w"
|
"warn"
=>
Level
::
Warn
,
"i"
|
"info"
=>
Level
::
Info
,
"d"
|
"debug"
=>
Level
::
Debug
,
"t"
|
"trace"
=>
Level
::
Trace
,
_
=>
panic!
(
"Fatal error : unknow log level !"
),
};
// Config logger
let
logger_config
=
Config
{
time
:
Some
(
Level
::
Error
),
level
:
Some
(
Level
::
Error
),
target
:
Some
(
Level
::
Debug
),
location
:
Some
(
Level
::
Debug
),
time_format
:
Some
(
"%Y-%m-%d %H:%M:%S%:z"
),
};
// Create log file if not exist
if
!
log_file_path
.as_path
()
.exists
()
{
File
::
create
(
log_file_path
.to_str
()
.expect
(
"Fatal error : fail to get log file path !"
),
)
.expect
(
"Fatal error : fail to create log file path !"
);
}
CombinedLogger
::
init
(
vec!
[
TermLogger
::
new
(
LevelFilter
::
Error
,
logger_config
)
.unwrap
(),
WriteLogger
::
new
(
log_level
.to_level_filter
(),
logger_config
,
OpenOptions
::
new
()
.write
(
true
)
.append
(
true
)
.open
(
log_file_path
.to_str
()
.expect
(
"Fatal error : fail to get log file path !"
),
)
.expect
(
"Fatal error : fail to open log file !"
),
),
])
.expect
(
"Fatal error : fail to init logger !"
);
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment