Compare commits

...

125 commits
v2.4.1 ... main

Author SHA1 Message Date
Expand-sys
8f85e13f11
Merge branch 'EntireTwix:main' into main 2023-01-23 01:41:58 +11:00
Expand-sys
7fcb761aa2 removed deployment script from ccash repo 2023-01-23 01:31:23 +11:00
EntireTwix
caf1d65e16 🐛 correcting last commit 2023-01-18 17:19:30 -08:00
EntireTwix
a61a590f3a cleaned up 2023-01-18 15:54:45 -08:00
EntireTwix
32f5f2a2be daemon flag error 2023-01-18 15:36:49 -08:00
EntireTwix
a98b84955c start is 0-indexed so == to data.size() is out of bounds 2023-01-12 16:51:09 -08:00
EntireTwix
c970b6a42f loosened endpoint restrictions 2023-01-12 16:33:01 -08:00
EntireTwix
f2da8cdbc2 optimizing GetLogsRange 2023-01-12 16:29:13 -08:00
EntireTwix
af551ef8b4 🐛 correcting last commit 2023-01-12 13:27:53 -08:00
EntireTwix
511aa76795 🐛 correcting last commit 2023-01-12 13:17:54 -08:00
EntireTwix
eea9c4b566 rest of log optimization 2023-01-12 12:26:42 -08:00
EntireTwix
cb5d12d4dc made GetLogsV2 newest to oldest transaction 2023-01-12 01:05:23 -08:00
EntireTwix
01aedef7a3 rest of log optimization 2023-01-12 00:55:08 -08:00
EntireTwix
6ddcf08797 📝 GetLogsRange 2023-01-12 00:33:35 -08:00
EntireTwix
4a41cb1ef4 🐛 how did this bug go unnoticed for so long 2023-01-12 00:31:03 -08:00
EntireTwix
dda98f346e GetLogsRange 2023-01-12 00:18:42 -08:00
EntireTwix
2419641cd0 🐛 fixed unsigned underflow when negative 2023-01-10 22:21:38 -08:00
EntireTwix
6dad3ed0af 📝 2023-01-10 22:13:59 -08:00
EntireTwix
88458de0f0 📝 added AdminGetLogs and reordered 2023-01-10 21:59:36 -08:00
EntireTwix
47649d6ccd AdminGetLogs 2023-01-10 21:58:05 -08:00
EntireTwix
370107e3f9 📝 ValidUsername should allow capitilization 2023-01-09 21:13:50 -08:00
EntireTwix
8fea062a3f 🐛 fixed 2023-01-09 18:37:40 -08:00
EntireTwix
779ab90b8f omega symbol 2023-01-09 17:30:25 -08:00
EntireTwix
0d346b820f 🐛 fixing last log commit 2023-01-09 17:10:41 -08:00
EntireTwix
c659c9b7bd 🐛 ValidUsername should allow capitilization 2023-01-09 17:01:14 -08:00
EntireTwix
5e996b2705 ImpactBal and SetBal add a log now 2023-01-09 16:43:54 -08:00
EntireTwix
7e1954d651 📝 2022-12-28 18:16:56 -08:00
Expand-sys
ad3bb2c13b allow ccash ports to be set by vars 2022-12-25 10:01:34 +11:00
William
b74510a113
🐛 invalid json after last commit 2022-12-24 00:55:21 -08:00
William
4aa55486c9
Merge pull request #50 from Expand-sys/patch-1
change default branch on deployment
2022-12-24 00:44:21 -08:00
Expand-sys
e413c089dc
change default branch on deployment 2022-12-24 19:19:14 +11:00
William
a195e8c5a2
Merge pull request #49 from EntireTwix/logs-optimization
Logs optimization
2022-12-23 19:33:45 -08:00
EntireTwix
396b676ee5 📝 updating GetLogsV2 docs 2022-12-23 19:32:28 -08:00
EntireTwix
dce87bbcfa Merge branch 'logs-optimization' of https://github.com/EntireTwix/CCash into logs-optimization 2022-12-23 19:07:41 -08:00
EntireTwix
705a746a3c 📝 157 bytes -> 139 2022-12-23 19:06:31 -08:00
EntireTwix
6e6d722f9f 📝 157 bytes -> 139 2022-12-23 19:05:26 -08:00
EntireTwix
70ac88e894 receiving does not have to be a json field 2022-12-23 19:03:08 -08:00
EntireTwix
6f1bd193d5 📝 2022-12-23 00:43:20 -08:00
EntireTwix
69a2f81454 📝 2022-12-20 17:20:28 -08:00
EntireTwix
113f42a399 📝 2022-12-20 16:58:19 -08:00
EntireTwix
3629b78e38 2022-12-20 15:34:57 -08:00
William
282bd5e423
Merge pull request #48 from EntireTwix/v2.5.1
V2.5.1
2022-12-20 13:35:18 -08:00
EntireTwix
b656bb7e43 📝 python lib up to date 2022-12-20 13:17:45 -08:00
EntireTwix
3b46c97d0a 📝 return_on_del is always a field now 2022-12-20 12:06:40 -08:00
EntireTwix
3e73d08227 🔥 return_on_del is always a field now 2022-12-20 11:56:50 -08:00
EntireTwix
82e3a6384c 📝 2022-12-19 20:07:49 -08:00
EntireTwix
d303016124 Merge branch 'v2.5.1' of https://github.com/EntireTwix/CCash into v2.5.1 2022-12-19 19:55:59 -08:00
EntireTwix
66b21332b3 🐛 fixed properties() 2022-12-19 19:55:52 -08:00
William
34039f9fcf
Merge pull request #47 from Expand-sys/v2.5.1
added pending changes to deployment script
2022-12-19 19:10:39 -08:00
Expand-sys
ce65a4387c made ccash use crontab to start it on boot 2022-12-20 14:01:55 +11:00
EntireTwix
95c2d47216 receiving output as "true" instead of "1" 2022-12-19 18:41:15 -08:00
Expand-sys
8696c5d870 added pending changes to deployment script 2022-12-20 13:35:34 +11:00
EntireTwix
dbe755da2b 📝 2022-12-19 17:47:41 -08:00
EntireTwix
24665641b4 📝 versioning changes 2022-12-19 17:44:49 -08:00
EntireTwix
026d2b8493 📝 versioning changes 2022-12-19 17:43:13 -08:00
EntireTwix
99f47dc6ed 📝 versioning changes 2022-12-19 17:31:38 -08:00
EntireTwix
d8e88ec375 📝 versioning documented 2022-12-19 16:26:00 -08:00
EntireTwix
8ff1fddf7a 📝 2022-12-19 16:07:34 -08:00
EntireTwix
07b9e20e31 expand's commit 2022-12-19 15:48:08 -08:00
EntireTwix
83455a0510 changed to per-method versioning 2022-12-19 15:45:05 -08:00
EntireTwix
cc103c7298 📝 2022-12-18 23:23:53 -08:00
EntireTwix
10c3c6a536 ✖️ -> 2022-12-18 22:27:29 -08:00
EntireTwix
21fd1c94e4 📝 connect services versioning documented 2022-12-18 22:26:44 -08:00
EntireTwix
b69092d732 📝 command line arguments example 2022-12-18 20:24:33 -08:00
EntireTwix
472a9222fc daemon flag 2022-12-18 20:16:52 -08:00
EntireTwix
878a71f310 🐛 fixing last commit 2022-12-18 19:11:26 -08:00
EntireTwix
411d1996c7 🐛 used CMake variables incorrectly 2022-12-18 19:09:55 -08:00
EntireTwix
722f8d0f48 🐛 correcting last commit 2022-12-18 18:35:26 -08:00
EntireTwix
aefdb4ce9b more accurate thread readout 2022-12-18 18:34:35 -08:00
EntireTwix
76388c6423 📝 mistaken ✖️ 2022-12-18 17:56:20 -08:00
EntireTwix
ff0dfc8a93 📝 2022-12-18 17:28:02 -08:00
EntireTwix
5e253e42d9 🐛 fixing last commit 2022-12-18 17:22:12 -08:00
EntireTwix
d63be0ec73 🐛 logs being disabled wasnt building 2022-12-18 17:18:47 -08:00
EntireTwix
4ca1bbe6eb 📝 2022-12-18 16:51:23 -08:00
EntireTwix
54acbf8cc6 🐛 "doc["time"].get(pass)" -> "doc["pass"].get(pass)" 2022-12-18 15:48:28 -08:00
EntireTwix
2c62c89b47 💡 clarifying comment 2022-12-18 13:22:46 -08:00
EntireTwix
37b110d36f 🐛 receiving field should not be in quotes 2022-12-17 12:25:47 -08:00
William
8e44a3d446
Update FAQ.md 2022-12-17 09:18:50 -08:00
William
e20ac4cebc
Merge pull request #45 from Expand-sys/main
updated the variables fle for ansible
2022-12-13 02:43:37 -08:00
Expand-sys
19b6acc48f
Merge branch 'EntireTwix:main' into main 2022-12-11 11:16:34 +11:00
Expand-sys
ed0d5c8231 update ansible to allow for api version changes 2022-12-11 11:14:55 +11:00
EntireTwix
6d9c6d6c1c 📝 corrected 2022-12-09 04:06:04 -08:00
EntireTwix
04fe7376ec 📝 2022-12-09 04:04:30 -08:00
EntireTwix
292b73001e 📝 simplified 2022-12-09 04:02:33 -08:00
EntireTwix
c8791ec7ce 📝 clarified path 2022-12-09 04:02:14 -08:00
EntireTwix
a308f830c0 📝 2022-12-04 00:40:04 -08:00
EntireTwix
a49a1730f7 🐛 fixed MIN_API_SUPPORT commit 2022-12-04 00:17:11 -08:00
EntireTwix
0b7de8b905 📝 doggo ->ArcNyxx 2022-12-04 00:07:04 -08:00
EntireTwix
b674a6dded 🎨 help and properties are version independent 2022-12-04 00:04:31 -08:00
EntireTwix
49b5b7d35d 📝 help and properties are version independent 2022-12-04 00:04:17 -08:00
EntireTwix
f9aa33afac updated ApiProperties 2022-12-03 23:56:07 -08:00
EntireTwix
da65fb678a 📝 MIN_API_SUPPORT 2022-12-03 23:55:20 -08:00
EntireTwix
7850c721e5 Merge branch 'v2' of https://github.com/EntireTwix/CCash into v2 2022-12-03 23:45:37 -08:00
EntireTwix
09422995e8 MIN_API_SUPPORT 2022-12-03 23:45:19 -08:00
William
d5f5b41e20
Merge pull request #44 from Expand-sys/patch-7
Update deploy.md
2022-12-03 18:09:32 -08:00
Expand-sys
7d4a564513
Update deploy.md
added ansible docs and changed docker link to use auto built docker image
2022-12-04 13:05:18 +11:00
EntireTwix
a68e86b216 📝 2022-11-30 20:37:31 -08:00
EntireTwix
a9e3ca1665 📝 backwards compatibility noted 2022-11-30 20:31:08 -08:00
EntireTwix
f6d8673045 🐛 GetLogsV2 also needs a log_flag 2022-11-30 20:14:25 -08:00
EntireTwix
206698697b 🐛 forgot usernames must be <3 characters 2022-11-30 20:14:11 -08:00
EntireTwix
f1b03ecb41 🐛 GetLogsV2 also needs a log_flag 2022-11-30 19:17:19 -08:00
EntireTwix
94c2cb1f65 🐛 used old log_snapshot 2022-11-30 19:14:22 -08:00
EntireTwix
7c31b4d680 GetLogsV2 and NumOfUsers output 2022-11-30 19:08:19 -08:00
EntireTwix
b874af86af 🐛 messed up RETURN_ON_DEL_NAME cmake var 2022-11-30 17:03:34 -08:00
EntireTwix
73a80de08e 🐛 broken cmake 2022-11-28 18:37:38 -08:00
EntireTwix
35c50ac0f4 📝 2022-11-28 18:20:21 -08:00
EntireTwix
4892ec2655 📝 2022-11-28 18:13:00 -08:00
EntireTwix
d46fe68559 📝 2022-11-28 18:12:00 -08:00
EntireTwix
52677f0576 API_VERSION settable from cmake 2022-11-28 18:02:14 -08:00
EntireTwix
d2f0989a15 📝 noting that existing apis dont support v2 2022-11-28 17:45:31 -08:00
EntireTwix
ecb602d6f2 📝 2022-11-28 17:43:43 -08:00
EntireTwix
a068502643 📝 updated endpoint logs for new GetLogV2 2022-11-28 17:41:38 -08:00
EntireTwix
49816dc18c updated at launch stats 2022-11-28 17:35:36 -08:00
EntireTwix
e100444042 🔥 temporary comment 2022-11-28 17:35:22 -08:00
EntireTwix
4fd3eb2bd8 📝 updated stats on log size in memory/disk 2022-11-28 17:34:52 -08:00
EntireTwix
cf4ba5ccfa api_version related changes 2022-11-28 17:14:41 -08:00
William
244ca2561c
Merge pull request #43 from EntireTwix/transaction_optimization
Transaction Optimization
2022-11-28 17:10:24 -08:00
EntireTwix
b584f5b4d5 improved Transaction structure 2022-11-28 17:06:13 -08:00
EntireTwix
ab27971d8e 💡 comment clarification 2022-11-28 16:41:27 -08:00
EntireTwix
7387156d15 🔥 unessasary macro 2022-11-28 16:41:08 -08:00
EntireTwix
47d544070b 💡 comment error and API_VERSION incremented 2022-11-28 16:40:07 -08:00
EntireTwix
1f983322a1 updated fbe for new transaction struct 2022-11-28 16:39:32 -08:00
EntireTwix
5a754a567c config file isnt subject to commits 2022-11-24 11:22:01 -08:00
EntireTwix
83f149677d 📝 2022-11-24 11:21:40 -08:00
William
61134740f0
📝 fixed rust api link 2022-11-24 09:45:00 -08:00
45 changed files with 733 additions and 524 deletions

3
.gitignore vendored
View file

@ -1,4 +1,5 @@
.vscode .vscode
build build
ccash_config.hpp ccash_config.hpp
deployment/.yamllint deployment/.yamllint
config

View file

@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
add_executable(${PROJECT_NAME} main.cpp ) add_executable(${PROJECT_NAME} main.cpp)
target_sources(${PROJECT_NAME} PRIVATE target_sources(${PROJECT_NAME} PRIVATE
src/bank_api.cpp src/bank_api.cpp
@ -75,12 +75,18 @@ endif()
if(DEFINED RETURN_ON_DEL_NAME) if(DEFINED RETURN_ON_DEL_NAME)
set(RETURN_ON_DEL_VAL true) set(RETURN_ON_DEL_VAL true)
set(RETURN_ON_DEL_NAME_VAL "\""${RETURN_ON_DEL_NAME}"\"") set(RETURN_ON_DEL_NAME_VAL "\"${RETURN_ON_DEL_NAME}\"")
else() else()
set(RETURN_ON_DEL_VAL false) set(RETURN_ON_DEL_VAL false)
set(RETURN_ON_DEL_NAME_VAL "\"\"") set(RETURN_ON_DEL_NAME_VAL "\"\"")
endif() endif()
if(DEFINED USE_DEPRECATED_ENDPOINTS)
set(USE_DEPRECATED_ENDPOINTS_VAL ${USE_DEPRECATED_ENDPOINTS})
else()
set(USE_DEPRECATED_ENDPOINTS_VAL true)
endif()
configure_file(ccash_config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/ccash_config.hpp) configure_file(ccash_config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/ccash_config.hpp)
target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC include)

View file

@ -3,14 +3,15 @@
* [problem/solution](docs/idea.md) * [problem/solution](docs/idea.md)
* connected services * connected services
* how to contribute * how to create
* [explanation](docs/connected_services/how_to/explanation.md) * [explanation](docs/connected_services/how_to/explanation.md)
* [language APIs](docs/connected_services/how_to/APIs.md) * [API implementations](docs/connected_services/how_to/APIs.md)
* [API endpoints](docs/connected_services/how_to/endpoints.md) * [the API](docs/connected_services/how_to/endpoints.md)
* [existing services](docs/connected_services/existing_services.md) * [existing services](docs/connected_services/existing_services.md)
* features * features
* [user side](docs/features/user_side.md) * [user side](docs/features/user_side.md)
* [implementation](docs/features/implementation.md) * [implementation](docs/features/implementation.md)
* [building](docs/building.md) * [building](docs/building.md)
* [FAQ](docs/FAQ.md) * [FAQ](docs/FAQ.md)
* [Liberapay](https://en.liberapay.com/EntireTwix/) if you wanna support this and/or future projects
* [Versions](docs/versioning.md)

View file

@ -61,10 +61,11 @@ using namespace std::chrono;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
for (size_t i = 0; i < 10000; ++i) for (size_t i = 100; i < 10100; ++i)
{ {
Bank::AddUser(std::to_string(i), 0, "root"); Bank::AddUser(std::to_string(i), 0, "root");
} }
std::cout << "added " << Bank::NumOfUsers() << " users\n";
Bank::AddUser("twix", 0, "root"); Bank::AddUser("twix", 0, "root");
Bank::AddUser("jolly", 0, "root"); Bank::AddUser("jolly", 0, "root");
Bank::admin_account = "twix"; Bank::admin_account = "twix";
@ -89,25 +90,16 @@ int main(int argc, char **argv)
Op(Bank::VerifyPassword("twix", "root"), "verify pass: ", 1000000); Op(Bank::VerifyPassword("twix", "root"), "verify pass: ", 1000000);
Op(Bank::ChangePassword("twix", "root"), "change pass: ", 1000000); Op(Bank::ChangePassword("twix", "root"), "change pass: ", 1000000);
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
Op(Bank::GetLogs("twix"), "get logs init: ", 1); Op(Bank::GetLogs("twix"), "get logs init: ", 1);
Op(Bank::GetLogs("twix"), "get logs cached: ", 1000000); Op(Bank::GetLogs("twix"), "get logs cached: ", 1000000);
#endif
Op(Bank::GetLogsV2("twix"), "get logs init (v2): ", 1);
Op(Bank::GetLogsV2("twix"), "get logs cached (v2): ", 1000000);
Op(Bank::GetLogsRange("twix", 0, 100), "get logs range: ", 1000000);
#endif #endif
Op(Bank::PruneUsers(0, 0), "prune users: ", 1); Op(Bank::PruneUsers(0, 0), "prune users: ", 1);
Op(Bank::Save(), "saving: ", 1); Op(Bank::Save(), "saving: ", 1);
//GetBal scalining test
//std::default_random_engine generator;
//std::uniform_real_distribution<double> distribution(0.0, 1.0);
// for (size_t i = 0; i < 10000000; ++i)
// {
// Bank::AddUser(std::to_string(i), 100000, "root");
// if (i % 10000 == 0)
// {
// auto u = std::to_string((int)(distribution(generator) * i));
// Op(Bank::GetBal(u), std::to_string(i) + ", ", 100000);
// }
// }
return 0; return 0;
} }

View file

@ -3,7 +3,7 @@
// Setting to 0 does not compile logging (useful for if disk/memory is very valuable) // Setting to 0 does not compile logging (useful for if disk/memory is very valuable)
#define MAX_LOG_SIZE @MAX_LOG_SIZE_VAL@ #define MAX_LOG_SIZE @MAX_LOG_SIZE_VAL@
//default to minecraft usernames // Default to minecraft usernames
constexpr unsigned min_name_size = 3; constexpr unsigned min_name_size = 3;
constexpr unsigned max_name_size = 16; constexpr unsigned max_name_size = 16;
@ -28,15 +28,8 @@ if false, when frequency is hit save
*/ */
#define CONSERVATIVE_DISK_SAVE @CONSERVATIVE_DISK_SAVE_VAL@ #define CONSERVATIVE_DISK_SAVE @CONSERVATIVE_DISK_SAVE_VAL@
/*
example, when set to 2
version 1 will not work
version 2 will work
version 3 will work
etc
*/
#define API_VERSION 1
#define MULTI_THREADED @MULTI_THREADED_VAL@ #define MULTI_THREADED @MULTI_THREADED_VAL@
#define ADD_USER_OPEN @ADD_USER_OPEN_VAL@ #define ADD_USER_OPEN @ADD_USER_OPEN_VAL@
#define USE_DEPRECATED_ENDPOINTS @USE_DEPRECATED_ENDPOINTS_VAL@

View file

@ -1,2 +0,0 @@
[all]
10.10.0.145 ansible_ssh_user=root ansible_ssh_common_args='-o StrictHostKeyChecking=no'

View file

@ -1,96 +0,0 @@
---
- hosts: all
vars:
become: true
pre_tasks:
- name: load variables
ansible.builtin.include_vars: '{{ item }}'
with_first_found:
- "default.yml"
tasks:
- name: refresh packages update
yum:
name: "*"
update_cache: true
state: latest
- name: Add repository
yum:
name: epel-release
state: latest
when: ansible_os_family == "RedHat"
- name: install dependencies
yum:
name: [git, gcc, gcc-c++, libuuid-devel, openssl-devel, zlib-devel, jsoncpp-devel, cmake]
state: present
when: ansible_os_family == "RedHat"
- name: clone CCash repository
git:
repo: https://github.com/EntireTwix/CCash.git
dest: '{{BUILD_DIR}}/CCash'
recursive: true
update: false
- name: Make lib base64
community.general.make:
chdir: '{{BUILD_DIR}}/CCash/third_party/base64'
params:
AVX2_CFLAGS: -mavx2
SSSE3_CFLAGS: -mssse3
SSE41_CFLAGS: -msse4.1
SSE42_CFLAGS: -msse4.2
AVX_CFLAGS: -mavx
- name: create build dir
file:
path: '{{BUILD_DIR}}/CCash/build'
state: directory
- name: Cmake CCash
ansible.builtin.command:
chdir: '{{BUILD_DIR}}/CCash/build'
cmd: |
cmake -DDROGON_CONFIG_LOC="{{ BUILD_DIR }}/CCash/config/config.json" -DUSER_SAVE_LOC="{{ BUILD_DIR }}/CCash/config/users.dat" ..
- name: make CCash
community.general.make:
chdir: '{{BUILD_DIR}}/CCash/build'
params:
NUM_THREADS: '-j{{ ansible_processor_vcpus }}'
- name: create users file
ansible.builtin.command:
chdir: '{{BUILD_DIR}}/CCash/build/'
cmd: ./bank
creates: '{{ BUILD_DIR }}/CCash/config/users.dat'
- name: chmod +x ssl.sh
ansible.builtin.file:
mode: u+x
path: '{{BUILD_DIR}}/CCash/config/ssl.sh'
- name: generate default ssl
ansible.builtin.command:
chdir: '{{BUILD_DIR}}/CCash/config/'
cmd: './ssl.sh'
- name: create service file
ansible.builtin.copy:
content: |
[Unit]
Description=CCash API Server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=simple
ExecStart={{BUILD_DIR}}/CCash/build/bank {{ADMIN_A}} {{SAVE_FREQ}}
ExecStop=/bin/kill -WINCH ${MAINPID}
KillSignal=SIGCONT
PrivateTmp=true
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/ccash.service

View file

@ -1,4 +0,0 @@
---
BUILD_DIR: '/root'
ADMIN_A: "admin"
SAVE_FREQ: "2"

View file

@ -1,41 +1,20 @@
[PREVIOUS PAGE](building.md) [PREVIOUS PAGE](building.md)
#### Q : How do I setup a CCash instance ### How do I setup a CCash instance
#### A : You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package. You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package.
### Why is my username invalid
Usernames are restricted by minecraft's requirements
#### Q : Why is my username invalid * letters
#### A : Usernames are restricted by minecraft's requirements
* lowercase letters
* numbers * numbers
* _ * _
* Length must be atleast 3 and at most 16 characters. * length must be atleast 3 and at most 16 characters.
### Is this crypto like krist?
CCash isn't a crypto, simply a ledger keeping track of who owns what.
#### Q : Is this a crypto like krist? ### Why isnt this on a database?
#### A : CCash isn't a crypto, the economy you decide to implement is entirely up to you. Because this usecase requires none of the features a database would offer.
### People are making too many accounts maliciously to fill up space on my server!
Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
#### Q : Why isnt this on a database? ### My instance is taking up too much storage or RAM
#### A : Because this usecase requires none of the features a database would offer. Reduce log size and/or use the prune users endpoint to remove dead accounts.
### Why not use an economy mod
Speed of operations, CCash being external to MC (and so compatible with any version/configuration), and the API are the main advantages to an economy mod.
#### Q : People are making too many accounts maliciously to fill up space on my server!
#### A : Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
#### Q : People are making too many transactions filling up space on my server!
#### A : Consider setting the variable `MAX_LOG_SIZE` to 0 in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
#### Q : My instance is taking up too much RAM
#### A : Reduce log size.
#### Q : My instance is taking up too much disk spac
#### A : Use the prune users endpoint to dead accounts or you can reduce log size but should be a last resort.
#### Q : My instance is slow
#### A : Toggling off logs will increase performance. On some devices multi threading increases performance, on others the overhead isn't worth the benefit.

View file

@ -5,11 +5,12 @@
as CCash is very lightweight it can run on practically any device but here are some tips: as CCash is very lightweight it can run on practically any device but here are some tips:
* single core machines should toggle `MULTI_THREADED` to `false` * single core machines should toggle `MULTI_THREADED` to `false`
* if your server is sufficiently active, such that each time save frequency is met, changes having been made is highly likely then `CONSERVATIVE_DISK_SAVE` should be toggled to `false` * if your server is sufficiently active, such that each time save frequency is met, changes having been made is highly likely then `CONSERVATIVE_DISK_SAVE` should be toggled to `false`
* `MAX_LOG_SIZE` should be adjusted as it takes up the most memory usage/storage of the ledger's features at ~203 bytes in memory and ~104 bytes in disk at default settings, so 5165 logs per Mb of RAM. Setting to 0 will disable logs * `MAX_LOG_SIZE` should be adjusted as it takes up the most memory usage/storage of the ledger's features at 139 bytes in memory and 43 bytes in disk at default settings on the current version, so 7543 logs per MB of RAM. Setting to 0 will disable logs
* with no users memory usage is 8.47 Mb * with no users memory usage is ~8.47 MB
* Saving frequency (a runtime argument) being set to 0 will disable frequency saving and only save on close * saving frequency being set to 0 will disable frequency saving and only save on close
* make backups of your save files!
## Docker ## Docker & Ansible
If you want to use the docker package, deploy information can be found [here](deploy.md) If you want to use the docker package, deploy information can be found [here](deploy.md)
## Drogon Depedencies ## Drogon Depedencies
@ -63,18 +64,18 @@ mkdir build
cd build cd build
``` ```
### CMake Flags ### CMake Variables
there are multiple flags responsible configuring CCash: there are multiple flags responsible configuring CCash:
| name | default | description | pros | cons | | name | default | description | pros | cons |
| :--------------------- | :-----------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- | | :----------------------- | :------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
| USER_SAVE_LOC | "users.dat" | where the users are saved | `N/A` | `N/A` | | USER_SAVE_LOC | "config/users.dat" | where the users are saved | `N/A` | `N/A` |
| DROGON_CONFIG_LOC | "config.json" | where the config is located | `N/A` | `N/A` | | DROGON_CONFIG_LOC | "config/config.json" | where the config is located | `N/A` | `N/A` |
| MAX_LOG_SIZE | 100 | max number of logs per user, last `n` transactions. If both this and pre log are toggled to 0 logs will not be compiled. | large history | higher memory usage | | MAX_LOG_SIZE | 100 | max number of logs per user, last `n` transactions. If both this and pre log are toggled to 0 logs will not be compiled. | large history | higher memory usage |
| CONSERVATIVE_DISK_SAVE | `true` | when `true` only saves when changes are made | low # of disk operations | some atomic overhead | | CONSERVATIVE_DISK_SAVE | `true` | when `true` only saves when changes are made | low # of disk operations | some atomic overhead |
| MULTI_THREADED | `true` | when `true` the program is compiled to utilize `n` threads which corresponds to how many Cores your CPU has, plus 1 for saving | speed | memory lock overhead is wasteful on single core machines | | MULTI_THREADED | `true` | when `true` the program is compiled to utilize `n` threads which corresponds to how many Cores your CPU has, plus 1 for saving | speed | memory lock overhead is wasteful on single core machines |
| RETURN_ON_DEL_NAME | `N/A` | when defined, return on delete will be toggled and any accounts deleted will send their funds to the defined account, this prevent currency destruction | prevents destruction of currency | deleting accounts is made slower | | RETURN_ON_DEL_NAME | `N/A` | when defined, return on delete will be toggled and any accounts deleted will send their funds to the defined account, this prevent currency destruction | prevents destruction of currency | deleting accounts is made slower |
| ADD_USER_OPEN | `true` | anybody can make a new account, if set to false only admins can add accounts via `AdminAddUser()` | `N/A` | spamming new users | | ADD_USER_OPEN | `true` | anybody can make a new account, if set to false only admins can add accounts via `AdminAddUser()` | `N/A` | spamming new users |
| USE_DEPRECATED_ENDPOINTS | `true` | some endpoints have newer versions making them obsolete but old programs might still call these endpoints so they are simply marked deprecated. | supports old programs | old endpoints can be ineffecient |
EXAMPLE: EXAMPLE:
``` ```
@ -93,6 +94,7 @@ cmake <flags of your choice or none> ..
make -j<threads> make -j<threads>
sudo ./bank sudo ./bank
``` ```
the last command generates a blank save file in your defined location.
## Certs ## Certs
make sure to edit `config.json` adding the certificate location if you're using HTTPS, I personally use [certbot](https://certbot.eff.org/). make sure to edit `config.json` adding the certificate location if you're using HTTPS, I personally use [certbot](https://certbot.eff.org/).
@ -142,4 +144,16 @@ leaving
] ]
} }
``` ```
**it is Highly recommened you secure your server**
## Usage
You can now run the program from the build location. For example
```
sudo ./bank admin 5
```
in this example CCash will be launched with the admin account named `"admin"`, and a saving frequency of every `5` minutes; without daemon being given its default is `false`.
Another example
```
sudo ./bank Kevin 0 true
```
in this example CCash will be launched with the admin account named `"Kevin"`, and a saving frequency of `0` meaning the server will only save when closed; daemon is set to `true` and so will be launched in the background.

View file

@ -1,24 +1,32 @@
[PREVIOUS PAGE](how_to/endpoints.md) | [NEXT PAGE](../features/user_side.md) [PREVIOUS PAGE](how_to/endpoints.md) | [NEXT PAGE](../features/user_side.md)
## Key
| description | symbol |
| :-----------------------: | :----------------- |
| supported | :heavy_check_mark: |
| uses deprecated endpoints | ⚠ |
| uses defunt endpoints | :no_entry: |
| in development | :hammer: |
## General ## General
| author | name | v1 | image | | author | name | support | image |
| :-------------------------------------- | ----------------------------------------------------------- | :----------------------: | :-------------------------------------------------------------------------------------------------------------: | | :-------------------------------------- | ----------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121337724-afe9fe80-c8d1-11eb-8851-23ec5e74cd26.png) | | [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121337724-afe9fe80-c8d1-11eb-8851-23ec5e74cd26.png) | |
| [Expand](https://github.com/Expand-sys) | [Discord Bot](https://github.com/Expand-sys/ccashbot) | :heavy_check_mark: | | | [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | |
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | :heavy_check_mark: | |
| [Sam](https://github.com/STBoyden) | [Market](https://github.com/STBoyden/market-api-2.0) | :heavy_multiplication_x: | |
## Minecraft ## Minecraft
| author | name | v1 | image | | author | name | support | image |
| :------------------------------------------ | --------------------------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: | | :------------------------------------------ | ---------------------------------------------------------------------------------------- | :----------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/120050327-de163700-bfd1-11eb-9d5a-f75c003e867c.png) | | [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/120050327-de163700-bfd1-11eb-9d5a-f75c003e867c.png) |
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121338034-fb041180-c8d1-11eb-8640-b18c141eb980.png) | | [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ | ![image](https://user-images.githubusercontent.com/31377881/121338034-fb041180-c8d1-11eb-8640-b18c141eb980.png) |
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121277361-4d6b1100-c885-11eb-87c8-cfebcf58da4f.png) | | [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121277361-4d6b1100-c885-11eb-87c8-cfebcf58da4f.png) |
| [Reactified](https://github.com/Reactified) | [Chunk Loader Shop](https://github.com/Reactified/rpm/tree/main/packages/forceload-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/209894520-f7183f45-bbac-40f3-9f95-043bda3c0097.png) ![image](https://user-images.githubusercontent.com/31377881/209894553-16ef7e04-52e7-4198-8a39-9ad2ada6eaf7.png) |
| [STBoyden](https://github.com/STBoyden) | [Commodities Exchange](https://github.com/STBoyden/ccash-market) | :hammer: | |
## Desired ## Desired
| idea | description | | idea | description |
| :----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | :-----------: | :------------------------------------------------------------- |
| Market | a platform to buy and sell items. | | Gambling | physical or digital casino. |
| Anonymous Payments | a service that allows for sending of funds annoymously, by first sending them to an intermediate account that is receiving and sending from many wallets as to obfuscate the fund's origin. | | Shipping | the infastructure to quickly send items across long distances. |
| Gambling | physical or digital casino. | | Mod or Plugin | a server-side mod |
| Shipping | the infastructure to quickly send items across long distances. |

View file

@ -1,13 +1,14 @@
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md) [PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
| author | language | | v1 | CCash is backwards compatible, so even if a language API does not support the newester version it can still call the old endpoints. Only when the major version increments are deprecated features made defunct (e.g `v1.0.0` -> `v2.0.0`), check the [endpoint docs](endpoints.md) to avoid using deprecated endpoints. For more information about versioning check out [versioning docs](../../versioning.md).
| :-------------------------------------------------------- | :------: | ------------------------------------------------------------------------- | :----------------------: | | author | language | | newest CCash supported version |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | :heavy_check_mark: | | :-------------------------------------------------------- | :--------: | -------------------------------------------------------------------- | :----------------------------: |
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | JS | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | :heavy_multiplication_x: | | [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | `v2.5.1` |
| [Doggo](https://github.com/FearlessDoggo21) | Python | [CCashPythonClient](https://github.com/FearlessDoggo21/CCashPythonClient) | :heavy_check_mark: | | [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://github.com/STBoyden/ccash-rs) | `v2.5.1` |
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://git.stboyden.com/STBoyden/ccash-rs) | :heavy_check_mark: | | [Doggo](https://github.com/ArcNyxx) | Python | [CCashPythonClient](https://github.com/ArcNyxx/ccash_python_client) | `v2.5.1` |
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | TypeScript | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | `v1.3.0` |
for example here is a demo program for the lua API by SpaceCat
here is a demo program for the lua API by SpaceCat
```lua ```lua
local ccash = require("ccash.api") local ccash = require("ccash.api")

View file

@ -10,115 +10,89 @@
`A` - Admin, same as `U` but in addition requires username supplied be equal to the admin account username `A` - Admin, same as `U` but in addition requires username supplied be equal to the admin account username
:heavy_check_mark: ⚠ - Deprecated endpoint
:heavy_multiplication_x:
:no_entry: - Defunct endpoint
## all error responses have JSON string along with them to describe ## all error responses have JSON string along with them to describe
### Usage endpoints ### Usage endpoints
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------- | ------------------------------------------------------------------------------ | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------------: | :----------------------: | :----------------------: | | :------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: |
| GetBal | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | | GetBal | `v2.3.0` | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :x: | :x: | :x: |
| GetLog | retrieves the logs of a given user, length varies by server configuration | `N/A` | api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | | GetLogs | `v2.3.0` | retrieves the logs of a given user, length varies by server configuration (oldest to newest transactions) | `N/A` | ⚠ api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| SendFunds | sends funds from the authenticated user to the user `{name}` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | GetLogsV2 | `v2.6.1` | retrieves the logs of a given user, length varies by server configuration (newest to oldest transactions) | `N/A` | api/v2/user/log | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| VerifyPassword | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | | GetLogsRange | `v2.6.1` | retrieves the logs of a given user, where `{start}` is the 0-indexed first log and `{length}` is the number of logs after that index. | `N/A` | api/v1/user/log_range | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| SendFunds | `v2.3.0` | sends funds from the authenticated user to the user `"name"` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ChangePassword | `v2.3.0` | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| VerifyPassword | `v2.3.0` | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
### Usage enpoint errors ### Usage enpoint errors
| name | 400 | 401 | 404 | 406 | | name | 400 | 401 | 404 | 406 |
| :------------- | :----------------------: | :----------------------: | :----------------------: | :----------------: | | :------------- | :----------------: | :----------------: | :----------------: | :----------------: |
| GetBal | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | | GetBal | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| GetLog | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| VerifyPassword | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
### Usage endpoint support | VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
`v` denoting the API version | ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| name | v1 |
| :------------- | :----------------: |
| GetBal | :heavy_check_mark: |
| GetLog | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: |
| VerifyPassword | :heavy_check_mark: |
### Meta Usage endpoints ### Meta Usage endpoints
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :---------: | :----------------------------: | :----------------: | :----------------: | :----------------------: | :----------------------: | | :------------------ | :---------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| ChangePassword | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | AdminGetLogs | `v2.6.1` | retreives the logs of a given user `{name}`, length varies by server configuration | `N/A` | api/v1/admin/user/log?name={name} | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| AdminChangePassword | changes the password of a given user `{name}` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | AdminChangePassword | `v2.3.0` | changes the password of a given user `"name"` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| SetBal | sets the balance of a given user `{name}` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | AdminVerifyAccount | `v2.3.0` | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| ImpactBal | modifies the user `{name}`'s balance by `{amount}` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | SetBal | `v2.3.0` | sets the balance of a given user `"name"` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ImpactBal | `v2.3.0` | modifies the user `"name"`'s balance by `"amount"` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### Meta Usage endpoint errors ### Meta Usage endpoint errors
| name | 400 | 401 | 404 | 406 | | name | 400 | 401 | 404 | 406 |
| :------------------ | :----------------: | :----------------: | :----------------------: | :----------------: | | :------------------ | :----------------: | :----------------: | :----------------: | :----------------: |
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | AdminGetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | AdminVerifyAccount | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
### Meta Usage endpoint support
| name | v1 |
| :------------------ | :----------------: |
| ChangePassword | :heavy_check_mark: |
| AdminChangePassword | :heavy_check_mark: |
| SetBal | :heavy_check_mark: |
| ImpactBal | :heavy_check_mark: |
### Sytem Usage endpoints ### Sytem Usage endpoints
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :----------------------------------------------------------------------------------: | :----------------------: | :----------------------: | :----------------------: | :----------------------: | | :------------ | :---------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| Help | redirects to GitHub projects Docs | `N/A` | api/v1/help | `GET` | 301 | `N/A` | `N/A` | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | | Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: |
| Close | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | | Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| Contains | checks wether a user exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | | Contains | `v2.3.0` | checks wether a given user `{name}` exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :x: |
| AdminVerifyAccount | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | | PruneUsers | `v2.3.0` | deletes users with most recent transactions older then `"time"` (if logs are enabled) and have less money then `"amount"` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| PruneUsers | deletes users with most recent transactions older then `{time}` (if logs are enabled) and have less money then `{amount}` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | ApiProperties | `v2.5.1` | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"max_log":uint64, "add_user_open":boolean, "return_on_del":string} | :heavy_check_mark: | :x: | :x: | :x: |
| ApiProperties | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"version":uint64,"max_log":uint64} and "return_on_del":string if feature is enabled | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
### System Usage endpoin errors ### System Usage endpoin errors
| name | 401 | 404 | 406 | | name | 401 | 404 | 406 |
| :----------------- | :----------------------: | :----------------------: | :----------------------: | | :------------ | :----------------: | :----------------: | :----------------: |
| Help | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | | Help | :x: | :x: | :x: |
| Close | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminVerifyAccount | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
| PruneUsers | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | | ApiProperties | :x: | :x: | :x: |
| ApiProperties | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
### System Usage endpoint support
| name | v1 |
| :----------------- | :----------------: |
| Help | :heavy_check_mark: |
| Close | :heavy_check_mark: |
| Contains | :heavy_check_mark: |
| AdminVerifyAccount | :heavy_check_mark: |
### Username Requirements ### Username Requirements
Valid Valid
* lowercase letters * letters
* numbers * numbers
* _ * _
* Length must be atleast 3 and at most 16 characters. * Length must be atleast 3 and at most 16 characters.
### User Management endpoints ### User Management endpoints
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------- | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------------: | :----------------------: | :----------------------: | | :----------- | :---------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | | AddUser | `v2.3.0` | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
| AdminAddUser | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | AdminAddUser | `v2.3.0` | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| DelSelf | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | | DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| AdminDelUser | deletes a given user `{name}` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | AdminDelUser | `v2.3.0` | deletes a given user `"name"` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### User Management endpoint errors ### User Management endpoint errors
| name | 400 | 401 | 404 | 406 | 409 | | name | 400 | 401 | 404 | 406 | 409 |
| :----------- | :----------------------: | :----------------------: | :----------------------: | :----------------: | :----------------------: | | :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | AddUser | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | | AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| DelSelf | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | | DelSelf | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | | AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### User Management endpoint support
| name | v1 |
| :----------- | :----------------: |
| AddUser | :heavy_check_mark: |
| AdminAddUser | :heavy_check_mark: |
| DelSelf | :heavy_check_mark: |
| AdminDelUser | :heavy_check_mark: |

View file

@ -1,10 +1,10 @@
# Contributors # Contributors
| name | work | | name | work |
| :------------------------------------------- | ---------------------------- | | :------------------------------------------- | ---------------------------------- |
| [Luke](https://github.com/LukeeeeBennett) | Docker package, JS API | | [Luke](https://github.com/LukeeeeBennett) | Github Actions, and JS API |
| [React](https://github.com/Reactified) | Logo, deprecated CCLua API | | [React](https://github.com/Reactified) | Logo, CC Wallet/Shop/ATM |
| [Doggo](https://github.com/FearlessDoggo21) | HTTP suggestions, Python API | | [Doggo](https://github.com/FearlessDoggo21) | HTTP advice, Python API, and C CLI |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API | | [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
| [Expand](https://github.com/Expand-sys) | Fixed docker package | | [Expand](https://github.com/Expand-sys) | Docker, and Ansible |
| [Sam](https://github.com/STBoyden) | Rust API | | [Sam](https://github.com/STBoyden) | Rust API |
| Caesay | Restful API suggestions | | Caesay | Restful API advice |

View file

@ -7,9 +7,23 @@ A pre-built docker image is supplied in the repos [GitHub Packages](https://gith
It can be run with docker like so: It can be run with docker like so:
``` ```
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> expandsys/ccash docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ghcr.io/entiretwix/ccash/ccash:latest
``` ```
## Ansible
Additionally CCash can be deployed to any infrastructure able to run Rocky/Alma Linux 8/9 x86_64 virtual or not, we will be eventually updating it to allow it to run on other OS's but for now RHEL is what works.
As CCash is intended to be run as root, the playbook is run also as root. The playbook also builds CCash from the latest github push, so there may be bugs.
In order to use the ansible playbook, clone the playbook to any pc with the ability to access the server through SSH and with Ansible installed, edit the inventory file to contain the IP address of the target server and run the following commands:
```ansible-galaxy install -r deployment/requirements.yml
```ansible-playbook -i deployment/inventory deployment/main.yml -k```
When this is complete the server will have ccash installed to the user dir, this is customizable in the vars/default.yml file along with the admin username and save frequency.
To start CCash run:
```systemctl start ccash```
To run ccash at start up run:
```systemctl enable ccash```
## Build ## Build
Previously this used GitHub Workflows, I(Expand) dont know how to do those but its not that hard to deploy stuff manually. To run the pre configured docker image run the above command and you are off to the races it will deploy a self signed certificate and use that for deployment. As this is not a user facing deployment the certificate is self signed and thus will throw an error on chrome, though this will still work if you ignore it. For production you should deploy with a reverse proxy and a correct certificate for your domain. Previously this used GitHub Workflows, I(Expand) dont know how to do those but its not that hard to deploy stuff manually. To run the pre configured docker image run the above command and you are off to the races it will deploy a self signed certificate and use that for deployment. As this is not a user facing deployment the certificate is self signed and thus will throw an error on chrome, though this will still work if you ignore it. For production you should deploy with a reverse proxy and a correct certificate for your domain.

View file

@ -4,15 +4,12 @@
## Performance ## Performance
#### Speed #### Speed
<!-- graphs --> <!-- graphs -->
Capable of processing thousands of requests per second, with no slow down as user size grows to the millions. Capable of processing thousands of requests per second, with little slow down as user size grows to the millions.
#### Lightweight #### Lightweight
<!-- specs --> <!-- specs -->
Low memory usage at 8 Mb baseline, and 203 bytes per new log. * Low memory usage at 8 MB baseline, and 139 bytes per new log.
* Extremely low CPU usage in the single digits of %.
Anecdotally I typically expierenced <1% CPU usage. * Small save files at typically a couple kb, easily shareable.
Small save files at typically a couple kb, easily shareable.
## Accessibility ## Accessibility
#### Connected Services #### Connected Services
as explained in earlier docs a ecosystem of connected services allows you many ways to utilize CCash. as explained in earlier docs a ecosystem of connected services allows you many ways to utilize CCash.
@ -32,3 +29,5 @@ each transaction is logged and the last `n` logs are stored, if set to 0 logs wi
by default this feature is off, but when enabled deleted account's funds will be redirected to a specified account rather then "burned" by default this feature is off, but when enabled deleted account's funds will be redirected to a specified account rather then "burned"
#### Configurable #### Configurable
as you can read in [building.md](../building.md) CCash is highly configurable. as you can read in [building.md](../building.md) CCash is highly configurable.
#### Game Independent
As CCash does not require an addition to the game in the form of a mod or plugin, it can be ran on any server.

View file

@ -6,26 +6,25 @@ While CCash can be used for anything that can interact with its API I think mine
The currency model most Minecraft Servers adopt if any, is resource based, usually diamonds. This model is fraught with issues however: The currency model most Minecraft Servers adopt if any, is resource based, usually diamonds. This model is fraught with issues however:
* The primary issue is minecraft worlds are infinite leading to hyper inflation as everyone accrues more diamonds. * The primary issue is minecraft worlds are infinite, leading to hyper inflation as everyone accrues more diamonds.
* There is no central authority minting the currency. Any consumer can introduce more diamonds to the system. * Some resources are passively reapable (e.g iron or gold), making the generation of currency a larger focus than that of creating value.
* Some resources are passively reapable, making the generation of currency a larger focus than that of creating products.
* Locality is required for transactions. * Locality is required for transactions.
* Theft is possible; ownership is possession based. * Theft is possible; ownership is physical possession based.
CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on. CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on, CCash can proccess thousands of requests per second.
The CCash instance can be external to the game server. The CCash instance can be external to the game server:
![image](external_diagram.png) ![image](external_diagram.png)
or on localhost: Or on localhost:
![image](localhost_diagram.png) ![image](localhost_diagram.png)
Running it local to the game server reduces latency for connected services. Fortunately CCash is sufficiently lightweight as to not impact performance on most setups. Running it local to the game server reduces latency for connected services and CCash is very lightweight and so will be a tiny proportion of the server's total computation.
**DISCLAIMER: ComputerCraft requires you add `127.0.0.1` to its config section `allowed_domains` if you're interacting with CCash locally** **DISCLAIMER: ComputerCraft requires you add `127.0.0.1` to its config section `allowed_domains` if you're interacting with CCash locally**
As CCash is just a means of keeping track of who has what, the economic system you use is entirely up to whomever hosts the instance. As CCash is just a means of keeping track of who has what, the economic system you use is entirely up to whomever hosts the instance.
It's suggested an admin should manage the instance to lower incentive to manipulate. I suggest an admin should manage the instance to lower incentive to manipulate balances.

12
docs/versioning.md Normal file
View file

@ -0,0 +1,12 @@
# Versioning
## Endpoint Version
When changing an existing endpoint in a breaking way the version will increment in the path e.g `api/v1/user/log` -> `api/v2/user/log`. If the change is non-breaking then extra parameters will simply be added to the endpoint. If the older version is marked deprecated it will be documented in [endpoints.md](connected_services/how_to/endpoints.md)
## Release Version
Major changes (e.g `v1.0.0` -> `v2.0.0`) denote a breaking change as all previously deprecated endpoints will now be made defunct and wont be built with that release.
Minor changes (e.g `v1.0.0` -> `v1.1.0`) denote a non-breaking change that adds or changes something about CCash.
Patches (e.g `v1.0.0` -> `v1.0.1`) denote bug fixes or docs changes.

View file

@ -2,8 +2,8 @@ package bank_dom
struct Transaction struct Transaction
{ {
string from = ""; string counterparty = "";
string to = ""; bool receiving = false;
uint32 amount = 0; uint32 amount = 0;
timestamp time; timestamp time;
} }

View file

@ -1,22 +1,24 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom.h" #include "bank_dom.h"
namespace bank_dom { namespace bank_dom {
Transaction::Transaction() Transaction::Transaction()
: from("") : counterparty("")
, to("") , receiving(false)
, amount((uint32_t)0ull) , amount((uint32_t)0ull)
, time((uint64_t)0ull) , time((uint64_t)0ull)
{} {}
Transaction::Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time) Transaction::Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time)
: from(arg_from) : counterparty(arg_counterparty)
, to(arg_to) , receiving(arg_receiving)
, amount(arg_amount) , amount(arg_amount)
, time(arg_time) , time(arg_time)
{} {}
@ -36,8 +38,8 @@ bool Transaction::operator<(const Transaction& other) const noexcept
void Transaction::swap(Transaction& other) noexcept void Transaction::swap(Transaction& other) noexcept
{ {
using std::swap; using std::swap;
swap(from, other.from); swap(counterparty, other.counterparty);
swap(to, other.to); swap(receiving, other.receiving);
swap(amount, other.amount); swap(amount, other.amount);
swap(time, other.time); swap(time, other.time);
} }
@ -45,8 +47,8 @@ void Transaction::swap(Transaction& other) noexcept
std::ostream& operator<<(std::ostream& stream, const Transaction& value) std::ostream& operator<<(std::ostream& stream, const Transaction& value)
{ {
stream << "Transaction("; stream << "Transaction(";
stream << "from="; stream << "\"" << value.from << "\""; stream << "counterparty="; stream << "\"" << value.counterparty << "\"";
stream << ",to="; stream << "\"" << value.to << "\""; stream << ",receiving="; stream << (value.receiving ? "true" : "false");
stream << ",amount="; stream << value.amount; stream << ",amount="; stream << value.amount;
stream << ",time="; stream << value.time; stream << ",time="; stream << value.time;
stream << ")"; stream << ")";

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -27,15 +29,15 @@ namespace bank_dom {
struct Transaction struct Transaction
{ {
std::string from; std::string counterparty;
std::string to; bool receiving;
uint32_t amount; uint32_t amount;
uint64_t time; uint64_t time;
size_t fbe_type() const noexcept { return 1; } size_t fbe_type() const noexcept { return 1; }
Transaction(); Transaction();
Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time); Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time);
Transaction(const Transaction& other) = default; Transaction(const Transaction& other) = default;
Transaction(Transaction&& other) = default; Transaction(Transaction&& other) = default;
~Transaction() = default; ~Transaction() = default;
@ -60,10 +62,12 @@ struct Transaction
} // namespace bank_dom } // namespace bank_dom
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Transaction> : ostream_formatter {};
#endif
template<> template<>
struct hash<bank_dom::Transaction> struct std::hash<bank_dom::Transaction>
{ {
typedef bank_dom::Transaction argument_type; typedef bank_dom::Transaction argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -75,8 +79,6 @@ struct hash<bank_dom::Transaction>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct Logs struct Logs
@ -111,10 +113,12 @@ struct Logs
} // namespace bank_dom } // namespace bank_dom
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Logs> : ostream_formatter {};
#endif
template<> template<>
struct hash<bank_dom::Logs> struct std::hash<bank_dom::Logs>
{ {
typedef bank_dom::Logs argument_type; typedef bank_dom::Logs argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -126,8 +130,6 @@ struct hash<bank_dom::Logs>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct User struct User
@ -164,10 +166,12 @@ struct User
} // namespace bank_dom } // namespace bank_dom
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::User> : ostream_formatter {};
#endif
template<> template<>
struct hash<bank_dom::User> struct std::hash<bank_dom::User>
{ {
typedef bank_dom::User argument_type; typedef bank_dom::User argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -179,8 +183,6 @@ struct hash<bank_dom::User>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct Global struct Global
@ -216,10 +218,12 @@ struct Global
} // namespace bank_dom } // namespace bank_dom
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <> struct fmt::formatter<bank_dom::Global> : ostream_formatter {};
#endif
template<> template<>
struct hash<bank_dom::Global> struct std::hash<bank_dom::Global>
{ {
typedef bank_dom::Global argument_type; typedef bank_dom::Global argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -231,8 +235,6 @@ struct hash<bank_dom::Global>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
} // namespace bank_dom } // namespace bank_dom

View file

@ -1,15 +1,17 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom_final_models.h" #include "bank_dom_final_models.h"
namespace FBE { namespace FBE {
FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
, from(buffer, 0) , counterparty(buffer, 0)
, to(buffer, 0) , receiving(buffer, 0)
, amount(buffer, 0) , amount(buffer, 0)
, time(buffer, 0) , time(buffer, 0)
{} {}
@ -17,8 +19,8 @@ FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset
size_t FinalModel<::bank_dom::Transaction>::fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept size_t FinalModel<::bank_dom::Transaction>::fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept
{ {
size_t fbe_result = 0 size_t fbe_result = 0
+ from.fbe_allocation_size(fbe_value.from) + counterparty.fbe_allocation_size(fbe_value.counterparty)
+ to.fbe_allocation_size(fbe_value.to) + receiving.fbe_allocation_size(fbe_value.receiving)
+ amount.fbe_allocation_size(fbe_value.amount) + amount.fbe_allocation_size(fbe_value.amount)
+ time.fbe_allocation_size(fbe_value.time) + time.fbe_allocation_size(fbe_value.time)
; ;
@ -38,14 +40,14 @@ size_t FinalModel<::bank_dom::Transaction>::verify_fields() const noexcept
size_t fbe_current_offset = 0; size_t fbe_current_offset = 0;
size_t fbe_field_size; size_t fbe_field_size;
from.fbe_offset(fbe_current_offset); counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = from.verify(); fbe_field_size = counterparty.verify();
if (fbe_field_size == std::numeric_limits<std::size_t>::max()) if (fbe_field_size == std::numeric_limits<std::size_t>::max())
return std::numeric_limits<std::size_t>::max(); return std::numeric_limits<std::size_t>::max();
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
to.fbe_offset(fbe_current_offset); receiving.fbe_offset(fbe_current_offset);
fbe_field_size = to.verify(); fbe_field_size = receiving.verify();
if (fbe_field_size == std::numeric_limits<std::size_t>::max()) if (fbe_field_size == std::numeric_limits<std::size_t>::max())
return std::numeric_limits<std::size_t>::max(); return std::numeric_limits<std::size_t>::max();
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
@ -79,13 +81,13 @@ size_t FinalModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction&
size_t fbe_current_size = 0; size_t fbe_current_size = 0;
size_t fbe_field_size; size_t fbe_field_size;
from.fbe_offset(fbe_current_offset); counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = from.get(fbe_value.from); fbe_field_size = counterparty.get(fbe_value.counterparty);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
to.fbe_offset(fbe_current_offset); receiving.fbe_offset(fbe_current_offset);
fbe_field_size = to.get(fbe_value.to); fbe_field_size = receiving.get(fbe_value.receiving);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
@ -116,13 +118,13 @@ size_t FinalModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transac
size_t fbe_current_size = 0; size_t fbe_current_size = 0;
size_t fbe_field_size; size_t fbe_field_size;
from.fbe_offset(fbe_current_offset); counterparty.fbe_offset(fbe_current_offset);
fbe_field_size = from.set(fbe_value.from); fbe_field_size = counterparty.set(fbe_value.counterparty);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
to.fbe_offset(fbe_current_offset); receiving.fbe_offset(fbe_current_offset);
fbe_field_size = to.set(fbe_value.to); fbe_field_size = receiving.set(fbe_value.receiving);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -60,8 +62,8 @@ private:
mutable size_t _offset; mutable size_t _offset;
public: public:
FinalModel<std::string> from; FinalModel<std::string> counterparty;
FinalModel<std::string> to; FinalModel<bool> receiving;
FinalModel<uint32_t> amount; FinalModel<uint32_t> amount;
FinalModel<uint64_t> time; FinalModel<uint64_t> time;
}; };

View file

@ -1,24 +1,26 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "bank_dom_models.h" #include "bank_dom_models.h"
namespace FBE { namespace FBE {
FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset) FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
, from(buffer, 4 + 4) , counterparty(buffer, 4 + 4)
, to(buffer, from.fbe_offset() + from.fbe_size()) , receiving(buffer, counterparty.fbe_offset() + counterparty.fbe_size())
, amount(buffer, to.fbe_offset() + to.fbe_size()) , amount(buffer, receiving.fbe_offset() + receiving.fbe_size())
, time(buffer, amount.fbe_offset() + amount.fbe_size()) , time(buffer, amount.fbe_offset() + amount.fbe_size())
{} {}
size_t FieldModel<::bank_dom::Transaction>::fbe_body() const noexcept size_t FieldModel<::bank_dom::Transaction>::fbe_body() const noexcept
{ {
size_t fbe_result = 4 + 4 size_t fbe_result = 4 + 4
+ from.fbe_size() + counterparty.fbe_size()
+ to.fbe_size() + receiving.fbe_size()
+ amount.fbe_size() + amount.fbe_size()
+ time.fbe_size() + time.fbe_size()
; ;
@ -37,8 +39,8 @@ size_t FieldModel<::bank_dom::Transaction>::fbe_extra() const noexcept
_buffer.shift(fbe_struct_offset); _buffer.shift(fbe_struct_offset);
size_t fbe_result = fbe_body() size_t fbe_result = fbe_body()
+ from.fbe_extra() + counterparty.fbe_extra()
+ to.fbe_extra() + receiving.fbe_extra()
+ amount.fbe_extra() + amount.fbe_extra()
+ time.fbe_extra() + time.fbe_extra()
; ;
@ -75,17 +77,17 @@ bool FieldModel<::bank_dom::Transaction>::verify_fields(size_t fbe_struct_size)
{ {
size_t fbe_current_size = 4 + 4; size_t fbe_current_size = 4 + 4;
if ((fbe_current_size + from.fbe_size()) > fbe_struct_size) if ((fbe_current_size + counterparty.fbe_size()) > fbe_struct_size)
return true; return true;
if (!from.verify()) if (!counterparty.verify())
return false; return false;
fbe_current_size += from.fbe_size(); fbe_current_size += counterparty.fbe_size();
if ((fbe_current_size + to.fbe_size()) > fbe_struct_size) if ((fbe_current_size + receiving.fbe_size()) > fbe_struct_size)
return true; return true;
if (!to.verify()) if (!receiving.verify())
return false; return false;
fbe_current_size += to.fbe_size(); fbe_current_size += receiving.fbe_size();
if ((fbe_current_size + amount.fbe_size()) > fbe_struct_size) if ((fbe_current_size + amount.fbe_size()) > fbe_struct_size)
return true; return true;
@ -141,17 +143,17 @@ void FieldModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fb
{ {
size_t fbe_current_size = 4 + 4; size_t fbe_current_size = 4 + 4;
if ((fbe_current_size + from.fbe_size()) <= fbe_struct_size) if ((fbe_current_size + counterparty.fbe_size()) <= fbe_struct_size)
from.get(fbe_value.from, ""); counterparty.get(fbe_value.counterparty, "");
else else
fbe_value.from = ""; fbe_value.counterparty = "";
fbe_current_size += from.fbe_size(); fbe_current_size += counterparty.fbe_size();
if ((fbe_current_size + to.fbe_size()) <= fbe_struct_size) if ((fbe_current_size + receiving.fbe_size()) <= fbe_struct_size)
to.get(fbe_value.to, ""); receiving.get(fbe_value.receiving, false);
else else
fbe_value.to = ""; fbe_value.receiving = false;
fbe_current_size += to.fbe_size(); fbe_current_size += receiving.fbe_size();
if ((fbe_current_size + amount.fbe_size()) <= fbe_struct_size) if ((fbe_current_size + amount.fbe_size()) <= fbe_struct_size)
amount.get(fbe_value.amount, (uint32_t)0ull); amount.get(fbe_value.amount, (uint32_t)0ull);
@ -203,8 +205,8 @@ void FieldModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe
void FieldModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept void FieldModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
{ {
from.set(fbe_value.from); counterparty.set(fbe_value.counterparty);
to.set(fbe_value.to); receiving.set(fbe_value.receiving);
amount.set(fbe_value.amount); amount.set(fbe_value.amount);
time.set(fbe_value.time); time.set(fbe_value.time);
} }

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: user_model.fbe // Source: user_model.fbe
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -72,8 +74,8 @@ private:
size_t _offset; size_t _offset;
public: public:
FieldModel<std::string> from; FieldModel<std::string> counterparty;
FieldModel<std::string> to; FieldModel<bool> receiving;
FieldModel<uint32_t> amount; FieldModel<uint32_t> amount;
FieldModel<uint64_t> time; FieldModel<uint64_t> time;
}; };

View file

@ -1,10 +1,24 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "fbe.h" #include "fbe.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <rpc.h>
#undef DELETE
#undef ERROR
#undef HOST_NOT_FOUND
#undef Yield
#undef min
#undef max
#undef uuid_t
#endif
namespace FBE { namespace FBE {
std::string buffer_t::base64encode() const std::string buffer_t::base64encode() const

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -41,7 +43,6 @@
#include <uuid/uuid.h> #include <uuid/uuid.h>
#undef HOST_NOT_FOUND #undef HOST_NOT_FOUND
#elif defined(_WIN32) || defined(_WIN64) #elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#undef DELETE #undef DELETE
#undef ERROR #undef ERROR
#undef HOST_NOT_FOUND #undef HOST_NOT_FOUND
@ -321,10 +322,20 @@ private:
} // namespace FBE } // namespace FBE
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <>
struct fmt::formatter<FBE::decimal_t> : formatter<std::string_view>
{
template <typename FormatContext>
auto format(const FBE::decimal_t& value, FormatContext& ctx) const
{
return formatter<string_view>::format((double)value, ctx);
}
};
#endif
template <> template <>
struct hash<FBE::decimal_t> struct std::hash<FBE::decimal_t>
{ {
typedef FBE::decimal_t argument_type; typedef FBE::decimal_t argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -337,8 +348,6 @@ struct hash<FBE::decimal_t>
} }
}; };
} // namespace std
namespace FBE { namespace FBE {
// Register a new enum-based flags macro // Register a new enum-based flags macro
@ -530,10 +539,20 @@ private:
} // namespace FBE } // namespace FBE
namespace std { #if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
template <>
struct fmt::formatter<FBE::uuid_t> : formatter<std::string_view>
{
template <typename FormatContext>
auto format(const FBE::uuid_t& value, FormatContext& ctx) const
{
return formatter<string_view>::format(value.string(), ctx);
}
};
#endif
template <> template <>
struct hash<FBE::uuid_t> struct std::hash<FBE::uuid_t>
{ {
typedef FBE::uuid_t argument_type; typedef FBE::uuid_t argument_type;
typedef size_t result_type; typedef size_t result_type;
@ -548,8 +567,6 @@ struct hash<FBE::uuid_t>
} }
}; };
} // namespace std
namespace FBE { namespace FBE {
// Fast Binary Encoding buffer based on the dynamic byte buffer // Fast Binary Encoding buffer based on the dynamic byte buffer

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "fbe_final_models.h" #include "fbe_final_models.h"

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
namespace FBE { namespace FBE {
@ -536,8 +538,8 @@ inline size_t FinalModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) c
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4); FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
for (size_t i = fbe_map_size; i-- > 0;) for (size_t i = fbe_map_size; i-- > 0;)
{ {
TKey key; TKey key = TKey();
TValue value; TValue value = TValue();
size_t offset_key = fbe_model_key.get(key); size_t offset_key = fbe_model_key.get(key);
fbe_model_key.fbe_shift(offset_key); fbe_model_key.fbe_shift(offset_key);
fbe_model_value.fbe_shift(offset_key); fbe_model_value.fbe_shift(offset_key);
@ -568,8 +570,8 @@ inline size_t FinalModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>&
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4); FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
for (size_t i = fbe_map_size; i-- > 0;) for (size_t i = fbe_map_size; i-- > 0;)
{ {
TKey key; TKey key = TKey();
TValue value; TValue value = TValue();
size_t offset_key = fbe_model_key.get(key); size_t offset_key = fbe_model_key.get(key);
fbe_model_key.fbe_shift(offset_key); fbe_model_key.fbe_shift(offset_key);
fbe_model_value.fbe_shift(offset_key); fbe_model_value.fbe_shift(offset_key);

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#include "fbe_models.h" #include "fbe_models.h"

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
#pragma once #pragma once

View file

@ -1,7 +1,9 @@
//------------------------------------------------------------------------------
// Automatically generated by the Fast Binary Encoding compiler, do not modify! // Automatically generated by the Fast Binary Encoding compiler, do not modify!
// https://github.com/chronoxor/FastBinaryEncoding // https://github.com/chronoxor/FastBinaryEncoding
// Source: FBE // Source: FBE
// Version: 1.7.0.0 // FBE version: 1.14.1.0
//------------------------------------------------------------------------------
namespace FBE { namespace FBE {
@ -618,8 +620,8 @@ inline void FieldModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) con
auto fbe_model = (*this)[0]; auto fbe_model = (*this)[0];
for (size_t i = fbe_map_size; i-- > 0;) for (size_t i = fbe_map_size; i-- > 0;)
{ {
TKey key; TKey key = TKey();
TValue value; TValue value = TValue();
fbe_model.first.get(key); fbe_model.first.get(key);
fbe_model.second.get(value); fbe_model.second.get(value);
values.emplace(key, value); values.emplace(key, value);
@ -640,8 +642,8 @@ inline void FieldModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& v
auto fbe_model = (*this)[0]; auto fbe_model = (*this)[0];
for (size_t i = fbe_map_size; i-- > 0;) for (size_t i = fbe_map_size; i-- > 0;)
{ {
TKey key; TKey key = TKey();
TValue value; TValue value = TValue();
fbe_model.first.get(key); fbe_model.first.get(key);
fbe_model.second.get(value); fbe_model.second.get(value);
values.emplace(key, value); values.emplace(key, value);

View file

@ -31,8 +31,8 @@ private:
static ChangeFlag<false> save_flag; static ChangeFlag<false> save_flag;
#endif #endif
//must grab as shared if the operation is gonna modify "users"'s size or can be caught in a intermediary state such as SendFunds() // must grab as shared if the operation is gonna modify "users"'s size or can be caught in a intermediary state such as SendFunds()
//must grab as unique if the operation is gonna user iterators // must grab as unique if the operation is gonna use user iterators
static std::shared_mutex iter_lock; static std::shared_mutex iter_lock;
public: public:
@ -43,16 +43,22 @@ public:
static size_t SumBal() noexcept; static size_t SumBal() noexcept;
static BankResponse GetBal(const std::string &name) noexcept; static BankResponse GetBal(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
static BankResponse GetLogs(const std::string &name) noexcept; static BankResponse GetLogs(const std::string &name) noexcept;
#endif #endif
static BankResponse GetLogsV2(const std::string &name) noexcept;
static BankResponse GetLogsRange(const std::string &name, size_t n, size_t m) noexcept;
#endif
static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept; static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept; static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept;
static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept; static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept;
static BankResponse SetBal(const std::string &name, uint32_t amount) noexcept; static BankResponse SetBal(const std::string &name, int64_t amount) noexcept;
static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept; static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
static bool Contains(const std::string &name) noexcept; static bool Contains(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept; static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept;
#else #else

View file

@ -11,21 +11,25 @@ using namespace drogon;
class api : public HttpController<api> class api : public HttpController<api>
{ {
public: public:
#if API_VERSION >= 1
static void GetBal(req_args, const std::string &name); static void GetBal(req_args, const std::string &name);
#if USE_DEPRECATED_ENDPOINTS
static void GetLogs(req_args); static void GetLogs(req_args);
#endif
static void GetLogsV2(req_args);
static void GetLogsRange(req_args, size_t start, size_t length);
static void SendFunds(req_args); static void SendFunds(req_args);
static void ChangePassword(req_args);
static void VerifyPassword(req_args); static void VerifyPassword(req_args);
static void ChangePassword(req_args); static void AdminGetLogs(req_args, const std::string& name);
static void AdminChangePassword(req_args); static void AdminChangePassword(req_args);
static void AdminVerifyAccount(req_args);
static void SetBal(req_args); static void SetBal(req_args);
static void ImpactBal(req_args); static void ImpactBal(req_args);
static void Help(req_args); static void Help(req_args);
static void Close(req_args); static void Close(req_args);
static void Contains(req_args, const std::string &name); static void Contains(req_args, const std::string &name);
static void AdminVerifyAccount(req_args);
static void PruneUsers(req_args); static void PruneUsers(req_args);
static void ApiProperties(req_args); static void ApiProperties(req_args);
@ -33,41 +37,55 @@ public:
static void AdminAddUser(req_args); static void AdminAddUser(req_args);
static void DelSelf(req_args); static void DelSelf(req_args);
static void AdminDelUser(req_args); static void AdminDelUser(req_args);
#endif
METHOD_LIST_BEGIN METHOD_LIST_BEGIN
#if API_VERSION >= 1
//Usage //Usage
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>"); METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>"); METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
#endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>", "UserFilter<false, true>");
#else #else
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>"); METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
#endif #endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>");
#endif
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32) METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>"); METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");
//Meta Usage //Meta Usage
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
METHOD_ADD(api::AdminChangePassword, "/v1/admin/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["pass"](string) METHOD_ADD(api::AdminChangePassword, "/v1/admin/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["pass"](string)
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32) METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32) METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
//System Usage //System Usage
METHOD_ADD(api::Help, "/v1/help", Get, Options); METHOD_ADD(api::Help, "/help", Get, Options);
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>"); METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options, "JsonFilter<false>"); METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::PruneUsers, "/v1/admin/prune_users", Post, "UserFilter<false, true>", "JsonFilter<true>"); //expects ["time"](int64) and ["amount"](uint32) METHOD_ADD(api::PruneUsers, "/v1/admin/prune_users", Post, "UserFilter<false, true>", "JsonFilter<true>"); //expects ["time"](int64) and ["amount"](uint32)
METHOD_ADD(api::ApiProperties, "/properties", Get, Options); METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
//User Managment //User Managment
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string) METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string)
METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) ["amount"](uint32) ["pass"](string) METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) ["amount"](uint32) ["pass"](string)
METHOD_ADD(api::DelSelf, "/v1/user/delete", Delete, Options, "UserFilter<true, false>", "JsonFilter<false>"); METHOD_ADD(api::DelSelf, "/v1/user/delete", Delete, Options, "UserFilter<true, false>", "JsonFilter<false>");
METHOD_ADD(api::AdminDelUser, "/v1/admin/user/delete", Delete, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) METHOD_ADD(api::AdminDelUser, "/v1/admin/user/delete", Delete, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string)
#endif
METHOD_LIST_END METHOD_LIST_END
}; };

View file

@ -10,12 +10,22 @@ using namespace simdjson;
struct Log struct Log
{ {
private: private:
#if USE_DEPRECATED_ENDPOINTS
ChangeFlag<true> log_flag; ChangeFlag<true> log_flag;
std::string log_snapshot = "null"; std::string log_snapshot = "null";
#endif
ChangeFlag<true> log_flag_v2;
std::string log_snapshot_v2 = "null";
public: public:
std::deque<Transaction> data; std::deque<Transaction> data;
std::string GetLogs() noexcept; #if USE_DEPRECATED_ENDPOINTS
void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept; std::string GetLogs(const std::string& name) noexcept;
#endif
std::string GetLogsV2() noexcept;
std::string GetLogsRange(size_t n, size_t m) noexcept;
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
}; };

View file

@ -1,6 +1,11 @@
#pragma once #pragma once
#include <string> #include <string>
/*
The intended use of this cursed class is in violating the encapsulation of std::string this class acts like std::string_view even though its stored in a std::string.
The reason this was needed is because sometimes we have a std::string_view instance and another library requires a const std::string& argument, forcing us to copy to a string before passing it, this copying is unnecessary.
*/
struct StrFromSV_Wrapper struct StrFromSV_Wrapper
{ {
std::string str; std::string str;

View file

@ -5,10 +5,11 @@
struct Transaction struct Transaction
{ {
std::string from = "", to = ""; std::string counterparty = "";
bool receiving = false;
uint32_t amount = 0; uint32_t amount = 0;
time_t time = 0; time_t time = 0;
Transaction() noexcept; Transaction() noexcept;
Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time) noexcept; Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
}; };

View file

@ -34,46 +34,48 @@ int main(int argc, char **argv)
uint8_t temp[16]{16, 0, 0, 0, 4}; uint8_t temp[16]{16, 0, 0, 0, 4};
users_save.write((char *)temp, 16); users_save.write((char *)temp, 16);
users_save.close(); users_save.close();
std::cout << "User save file generated\nUsage: sudo ./bank <admin account> <saving frequency in minutes>\n"; std::cout << "User save file generated\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return 0;
} }
else else
{ {
std::cerr << "File cannot be created (may already exist)\n"; std::cerr << "File cannot be created (may already exist)\n";
return -1;
} }
return 0;
} }
if (argc != 3) if (argc < 3)
{ {
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes>\n"; std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return 0; return -1;
} }
if (geteuid() != 0) if (geteuid() != 0)
{ {
std::cerr << "ERROR: CCash MUST be ran as root\n"; std::cerr << "ERROR: CCash MUST be ran as root\n";
return 0; return -1;
} }
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
std::cout std::cout
<< "\nAPI Version : " << API_VERSION << "\nAPI : v2.6.1\n"
<< "\n\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled") << "\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
<< "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled") << "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled")
<< "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled") << "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled")
<< "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled") << "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled")
<< "\nSSE 4.1 : " << (__builtin_cpu_supports("sse4.1") ? "enabled" : "disabled") << "\nSSE 4.1 : " << (__builtin_cpu_supports("sse4.1") ? "enabled" : "disabled")
<< "\nSSE 4.2 : " << (__builtin_cpu_supports("sse4.2") ? "enabled" : "disabled") << "\nSSE 4.2 : " << (__builtin_cpu_supports("sse4.2") ? "enabled" : "disabled")
#if MULTI_THREADED #if MULTI_THREADED
<< "\n\nThreads : " << get_nprocs() + 1 << "\n\nThreads : " << get_nprocs() + saving_freq
<< "\nMulti threading : enabled"; << "\nMulti threading : enabled";
#else #else
<< "\n\nThreads : " << 2 << "\n\nThreads : " << 1 + saving_freq
<< "\nMulti threading : disabled"; << "\nMulti threading : disabled";
#endif #endif
//Loading users from users.json //Loading users from users.dat
Bank::Load(); Bank::Load();
size_t num_of_logs = Bank::NumOfLogs(); size_t num_of_logs = Bank::NumOfLogs();
size_t num_of_users = Bank::NumOfUsers(); size_t num_of_users = Bank::NumOfUsers();
std::cout << "\n\nLoaded " << num_of_users << " Users ~" << (float)(sizeof(User) * num_of_users) / 1048576 << "Mb" std::cout << "\n\nLoaded " << num_of_users << " Users ~" << (float)(sizeof(User) * num_of_users) / 1048576 << "MB"
<< "\nLoaded " << num_of_logs << " Logs ~" << (float)(num_of_logs * (91 + 80 + (max_name_size * 2))) / 1048576 << "Mb" //91:string representation(heap), sizeof(Transaction), max_name_size*2:filled to&from(heap) << "\nLoaded " << num_of_logs << " Logs ~" << (float)(num_of_logs * (75 + sizeof(Transaction) + max_name_size)) / 1048576 << "MB" //75:cached response per log(heap), sizeof(Transaction), max_name_size:counterparty(heap)
<< "\nLoaded " << Bank::SumBal() << " C$H" << "\nLoaded " << Bank::SumBal() << " C$H"
<< std::endl; //flushing before EventLoop << std::endl; //flushing before EventLoop
@ -88,19 +90,24 @@ int main(int argc, char **argv)
Bank::admin_account = argv[1]; Bank::admin_account = argv[1];
//Auto Saving //Auto Saving
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
if (saving_freq) //if saving frequency is 0 then auto saving is turned off if (saving_freq) //if saving frequency is 0 then auto saving is turned off
{ {
std::thread([saving_freq]() std::thread([saving_freq]()
{ {
while (1) while (1)
{ {
std::this_thread::sleep_for(std::chrono::minutes(saving_freq)); std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
std::cout << "Saving " << std::time(0) << "...\n" std::cout << "Saving " << std::time(0) << "...\n" << Bank::Save();
<< Bank::Save(); }
} })
}) .detach();
.detach(); }
if (argc == 4 && !strcmp(argv[3], "true")) { app().enableRunAsDaemon(); }
else if (argc == 4 && strcmp(argv[3], "false"))
{
std::cerr << "daemon flag must be \"true\" or \"false\"\n";
return -1;
} }
} //destroying setup variables } //destroying setup variables

View file

@ -36,7 +36,7 @@ inline bool ValidUsername(const std::string &name) noexcept
} }
for (char c : name) for (char c : name)
{ {
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')) if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{ {
return false; return false;
} }
@ -85,11 +85,14 @@ BankResponse Bank::GetBal(const std::string &name) noexcept
return {k200OK, std::to_string(res)}; return {k200OK, std::to_string(res)};
} }
} }
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
BankResponse Bank::GetLogs(const std::string &name) noexcept BankResponse Bank::GetLogs(const std::string &name) noexcept
{ {
BankResponse res; BankResponse res;
if (!Bank::users.modify_if(name, [&res](User &u) { res = {k200OK, u.log.GetLogs()}; })) if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; }))
{ {
return {k404NotFound, "\"User not found\""}; return {k404NotFound, "\"User not found\""};
} }
@ -99,6 +102,44 @@ BankResponse Bank::GetLogs(const std::string &name) noexcept
} }
} }
#endif #endif
BankResponse Bank::GetLogsV2(const std::string &name) noexcept
{
BankResponse res;
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogsV2()}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
BankResponse Bank::GetLogsRange(const std::string &name, size_t start, size_t length) noexcept
{
BankResponse res;
if (start >= MAX_LOG_SIZE)
{
return {k400BadRequest, "\"Invalid {start} index\""};
}
if (!length)
{
return {k400BadRequest, "\"Invalid {length}\""};
}
if (!Bank::users.modify_if(name, [&name, &res, start, length](User &u) { res = {k200OK, u.log.GetLogsRange(start, length)}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
#endif
BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept
{ {
if (!amount) if (!amount)
@ -123,7 +164,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a) if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a)
#endif #endif
{ {
//if A can afford it //if "A" can afford it
if (a.balance < amount) if (a.balance < amount)
{ {
res = {k400BadRequest, "\"Insufficient funds\""}; res = {k400BadRequest, "\"Insufficient funds\""};
@ -132,7 +173,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
{ {
a.balance -= amount; a.balance -= amount;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
a.log.AddTrans(a_name, b_name, amount, current_time); a.log.AddTrans(b_name, false, amount, current_time);
#endif #endif
res = {k200OK, std::to_string(a.balance)}; res = {k200OK, std::to_string(a.balance)};
} }
@ -145,7 +186,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) { Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
b.balance += amount; b.balance += amount;
b.log.AddTrans(a_name, b_name, amount, current_time); b.log.AddTrans(a_name, true, amount, current_time);
}); });
#else #else
Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; }); Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; });
@ -160,15 +201,20 @@ bool Bank::VerifyPassword(const std::string &name, const std::string_view &attem
Bank::users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); }); Bank::users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); });
return res; return res;
} }
void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept
{ {
SET_CHANGES_ON; SET_CHANGES_ON;
Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); }); Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); });
} }
BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept BankResponse Bank::SetBal(const std::string &name, int64_t amount) noexcept
{ {
if (ValidUsername(name) && Bank::users.modify_if(name, [amount](User &u) { u.balance = amount; })) if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) {
amount -= u.balance;
u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{ {
SET_CHANGES_ON; SET_CHANGES_ON;
return {k204NoContent, std::nullopt}; //returns new balance return {k204NoContent, std::nullopt}; //returns new balance
@ -185,7 +231,13 @@ BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept
return {k400BadRequest, "\"Amount cannot be 0\""}; return {k400BadRequest, "\"Amount cannot be 0\""};
} }
uint32_t bal; uint32_t bal;
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, amount](User &u) { bal = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); })) if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, &amount](User &u) {
if (u.balance < (amount * -1)) { amount = -int64_t(u.balance); };
bal = u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{ {
SET_CHANGES_ON; SET_CHANGES_ON;
return {k200OK, std::to_string(bal)}; //may return new balance return {k200OK, std::to_string(bal)}; //may return new balance
@ -212,15 +264,26 @@ BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept
#endif #endif
for (const auto &u : users) for (const auto &u : users)
{ {
#if MAX_LOG_SIZE > 0
#if RETURN_ON_DEL #if RETURN_ON_DEL
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) { if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) {
bal += u.balance; bal += u.balance;
#else #else
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) { if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) {
#endif #endif
#if MAX_LOG_SIZE > 0
return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal); return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal);
#else #else
#if RETURN_ON_DEL
if (Bank::users.erase_if(u.first, [threshold_bal, &bal, &deleted_count](User &u) {
bal += u.balance;
#else
if (Bank::users.erase_if(u.first, [threshold_bal, &deleted_count](User &u) {
#endif
return (u.balance < threshold_bal); return (u.balance < threshold_bal);
#endif #endif
})) }))

View file

@ -1,12 +1,10 @@
#include "bank_api.h" #include "bank_api.h"
// TODO: parser iterate(input).get(doc) error handling might be superfulous
#define CACHE_FOREVER resp->setExpiredTime(0) #define CACHE_FOREVER resp->setExpiredTime(0)
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*") #define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
static thread_local ondemand::parser parser; thread_local ondemand::parser parser;
#define SIMD_JSON_GEN \ #define SIMD_JSON_GEN \
simdjson::padded_string input(req->getBody()); \ simdjson::padded_string input(req->getBody()); \
ondemand::document doc; ondemand::document doc;
@ -24,13 +22,13 @@ static thread_local ondemand::parser parser;
#define NAME_PARAM req->getParameter("name") #define NAME_PARAM req->getParameter("name")
#if API_VERSION >= 1
//Usage //Usage
void api::GetBal(req_args, const std::string &name) void api::GetBal(req_args, const std::string &name)
{ {
RESPONSE_PARSE(Bank::GetBal(name)); RESPONSE_PARSE(Bank::GetBal(name));
} }
#if USE_DEPRECATED_ENDPOINTS
void api::GetLogs(req_args) void api::GetLogs(req_args)
{ {
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
@ -42,6 +40,44 @@ void api::GetLogs(req_args)
callback(resp); callback(resp);
#endif #endif
} }
#endif
void api::GetLogsV2(req_args)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(NAME_PARAM));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::GetLogsRange(req_args, size_t start, size_t length)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsRange(NAME_PARAM, start, length));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::AdminGetLogs(req_args, const std::string& name)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(name));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::SendFunds(req_args) void api::SendFunds(req_args)
{ {
SIMD_JSON_GEN; SIMD_JSON_GEN;
@ -80,7 +116,7 @@ void api::ChangePassword(req_args)
else else
{ {
std::string_view pass; std::string_view pass;
if (doc["time"].get(pass)) if (doc["pass"].get(pass))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
} }
@ -104,7 +140,7 @@ void api::AdminChangePassword(req_args)
else else
{ {
std::string_view name, pass; std::string_view name, pass;
if (doc["name"].get(name) || doc["time"].get(pass)) if (doc["name"].get(name) || doc["pass"].get(pass))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
} }
@ -206,15 +242,7 @@ void api::AdminVerifyAccount(req_args)
} }
void api::ApiProperties(req_args) void api::ApiProperties(req_args)
{ {
std::string info = "{\"version\":" + std::to_string(API_VERSION) + ",\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"add_user_open\":" + std::to_string(ADD_USER_OPEN); std::string info = "{\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"add_user_open\":" + (ADD_USER_OPEN?"true":"false") + ",\"return_on_del\":" + (RETURN_ON_DEL?'\"' + std::string(return_account) + "\"":"null") + '}';
if constexpr (RETURN_ON_DEL)
{
info += ",\"return_on_del\":\"" + std::string(return_account) + "\"}";
}
else
{
info += "}";
}
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)}); auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)});
CORS; CORS;
CACHE_FOREVER; CACHE_FOREVER;
@ -230,9 +258,9 @@ void api::PruneUsers(req_args)
} }
else else
{ {
uint64_t amount;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
int64_t time; int64_t time;
uint64_t amount;
if (doc["time"].get(time) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max())) if (doc["time"].get(time) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
@ -242,7 +270,6 @@ void api::PruneUsers(req_args)
res = Bank::PruneUsers(time, amount); res = Bank::PruneUsers(time, amount);
} }
#else #else
uint64_t amount
if (doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max())) if (doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
@ -303,7 +330,7 @@ void api::AdminAddUser(req_args)
std::string_view name; std::string_view name;
uint64_t amount; uint64_t amount;
std::string_view pass; std::string_view pass;
if (doc["name"].get(name) || doc["amount"].get(amount) || doc["time"].get(pass) || (amount > std::numeric_limits<uint32_t>::max())) if (doc["name"].get(name) || doc["amount"].get(amount) || doc["pass"].get(pass) || (amount > std::numeric_limits<uint32_t>::max()))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
} }
@ -344,4 +371,3 @@ void api::AdminDelUser(req_args)
} }
RESPONSE_PARSE(std::move(res)); RESPONSE_PARSE(std::move(res));
} }
#endif

View file

@ -1,22 +1,27 @@
#include "log.h" #include "log.h"
void Log::AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept
{ {
#if USE_DEPRECATED_ENDPOINTS
log_flag.SetChangesOn(); log_flag.SetChangesOn();
#endif
log_flag_v2.SetChangesOn();
if (data.size() == MAX_LOG_SIZE) if (data.size() == MAX_LOG_SIZE)
{ {
data.pop_back(); data.pop_front();
} }
data.emplace_back(from, to, amount, time); data.emplace_back(counterparty_str, receiving, amount, time);
} }
std::string Log::GetLogs() noexcept #if USE_DEPRECATED_ENDPOINTS
std::string Log::GetLogs(const std::string& name) noexcept
{ {
if (log_flag.GetChangeState() && data.size()) //if there are changes if (log_flag.GetChangeState() && data.size()) // if there are changes
{ {
log_snapshot.resize(0); log_snapshot.resize(0);
//re-generate snapshot //re-generate snapshot
size_t predicted_size = ((59 + (2 * max_name_size)) * data.size()) + 1; size_t predicted_size = ((57 + (2 * max_name_size)) * data.size()) + 1;
if (log_snapshot.capacity() < predicted_size) if (log_snapshot.capacity() < predicted_size)
{ {
log_snapshot.reserve(predicted_size); log_snapshot.reserve(predicted_size);
@ -24,18 +29,140 @@ std::string Log::GetLogs() noexcept
log_snapshot = '['; //1 log_snapshot = '['; //1
for (size_t i = 0; i < data.size(); ++i) for (size_t i = 0; i < data.size(); ++i)
{ {
log_snapshot += "{\"to\":\""; //8 log_snapshot += "{\"to\":\""; //7
log_snapshot += data[i].to; //max_name_size? log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
log_snapshot += "\",\"from\":\""; //10 log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].from; //max_name_size? log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
log_snapshot += "\",\"amount\":"; //12 log_snapshot += "\",\"amount\":"; //11
log_snapshot += std::to_string(data[i].amount); //10? log_snapshot += std::to_string(data[i].amount); //10?
log_snapshot += ",\"time\":"; //8 log_snapshot += ",\"time\":"; //8
log_snapshot += std::to_string(data[i].time); //10? log_snapshot += std::to_string(data[i].time); //10?
log_snapshot += "},"; //2 log_snapshot += "},"; //2
} }
log_snapshot.back() = ']'; log_snapshot.back() = ']';
log_flag.SetChangesOff(); log_flag.SetChangesOff();
} }
return log_snapshot; return log_snapshot;
} }
#endif
std::string Log::GetLogsV2() noexcept
{
if (log_flag_v2.GetChangeState() && data.size()) // if there are changes
{
log_snapshot_v2.resize(0);
//re-generate snapshot
size_t predicted_size = ((59 + max_name_size) * data.size()) + 1;
if (log_snapshot_v2.capacity() < predicted_size)
{
log_snapshot_v2.reserve(predicted_size);
}
log_snapshot_v2 = '['; //1
for (size_t i = data.size(); i --> 0;)
{
log_snapshot_v2 += "{\"counterparty\":\""; //17
log_snapshot_v2 += data[i].counterparty; //max_name_size?
log_snapshot_v2 += "\",\"amount\":"; //11
if (!data[i].receiving) { log_snapshot_v2 += '-'; } //1
log_snapshot_v2 += std::to_string(data[i].amount); //10?
log_snapshot_v2 += ",\"time\":"; //8
log_snapshot_v2 += std::to_string(data[i].time); //10?
log_snapshot_v2 += "},"; //2
}
log_snapshot_v2.back() = ']';
log_flag_v2.SetChangesOff();
}
return log_snapshot_v2;
}
std::string Log::GetLogsRange(size_t start, size_t length) noexcept
{
if (start >= data.size()) { return "[]"; }
if (start == 0 && length == MAX_LOG_SIZE) { return log_snapshot_v2; }
if (log_flag_v2.GetChangeState() && data.size()) { GetLogsV2(); }
size_t log_index_n, i;
if (start < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "a\n";
i = 0;
log_index_n = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_n == start)
{
log_index_n = i;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_n;
}
}
else
{
// std::cout << "b\n";
i = log_snapshot_v2.size();
log_index_n = data.size();
while(i --> 0)
{
if (log_index_n == start)
{
log_index_n = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_n;
}
}
size_t log_index_m = std::string::npos;
if ((start + length) < data.size())
{
if (length < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "c\n";
log_index_m = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_m;
}
}
else
{
// std::cout << "d\n";
i = log_snapshot_v2.size();
log_index_m = data.size();
while(i --> 0)
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_m;
}
}
log_index_m -= log_index_n;
}
std::string res(log_snapshot_v2.substr(log_index_n, log_index_m));
res[0] = '[';
res[res.size() - 1] = ']';
// std::cout << res << '\n';
return res;
}

View file

@ -1,4 +1,4 @@
#include "transaction.h" #include "transaction.h"
Transaction::Transaction() noexcept {}; Transaction::Transaction() noexcept {};
Transaction::Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time_val) noexcept : from(from_str), to(to_str), amount(amount), time(time_val) {} Transaction::Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {}

View file

@ -29,7 +29,7 @@ User::User(const bank_dom::User &u) noexcept : balance(u.balance), password(u.pa
for (; i < u.logs.value().data.size(); ++i) for (; i < u.logs.value().data.size(); ++i)
{ {
const bank_dom::Transaction &temp = u.logs.value().data[i]; const bank_dom::Transaction &temp = u.logs.value().data[i];
log.data.emplace_front(temp.from, temp.to, temp.amount, temp.time); log.data.emplace_front(temp.counterparty, temp.receiving, temp.amount, temp.time);
} }
} }
#endif #endif
@ -43,7 +43,7 @@ bank_dom::User User::Encode() const noexcept
save_log.data.reserve(this->log.data.size()); save_log.data.reserve(this->log.data.size());
for (const Transaction &t : this->log.data) for (const Transaction &t : this->log.data)
{ {
save_log.data.emplace_back(t.from, t.to, t.amount, t.time); save_log.data.emplace_back(t.counterparty, t.receiving, t.amount, t.time);
} }
return bank_dom::User(balance, password, save_log); return bank_dom::User(balance, password, save_log);
} }

View file

@ -8,7 +8,7 @@ inline bool ValidUsername(const std::string &name) noexcept
} }
for (char c : name) for (char c : name)
{ {
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')) if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{ {
return false; return false;
} }