Compare commits

..

No commits in common. "main" and "v2.4.1" have entirely different histories.
main ... v2.4.1

45 changed files with 524 additions and 733 deletions

1
.gitignore vendored
View file

@ -2,4 +2,3 @@
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,18 +75,12 @@ 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,15 +3,14 @@
* [problem/solution](docs/idea.md) * [problem/solution](docs/idea.md)
* connected services * connected services
* how to create * how to contribute
* [explanation](docs/connected_services/how_to/explanation.md) * [explanation](docs/connected_services/how_to/explanation.md)
* [API implementations](docs/connected_services/how_to/APIs.md) * [language APIs](docs/connected_services/how_to/APIs.md)
* [the API](docs/connected_services/how_to/endpoints.md) * [API endpoints](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,11 +61,10 @@ using namespace std::chrono;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
for (size_t i = 100; i < 10100; ++i) for (size_t i = 0; i < 10000; ++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";
@ -90,16 +89,25 @@ 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,8 +28,15 @@ 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@

2
deployment/inventory Normal file
View file

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

96
deployment/main.yml Normal file
View file

@ -0,0 +1,96 @@
---
- 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

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

View file

@ -1,20 +1,41 @@
[PREVIOUS PAGE](building.md) [PREVIOUS PAGE](building.md)
### How do I setup a CCash instance #### Q : How do I setup a CCash instance
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. #### 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.
### Why is my username invalid
Usernames are restricted by minecraft's requirements
* letters #### Q : Why is my username invalid
#### 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.
### Why isnt this on a database? #### Q : Is this a crypto like krist?
Because this usecase requires none of the features a database would offer. #### A : CCash isn't a crypto, the economy you decide to implement is entirely up to you.
### 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).
### My instance is taking up too much storage or RAM #### Q : Why isnt this on a database?
Reduce log size and/or use the prune users endpoint to remove dead accounts. #### A : Because this usecase requires none of the features a database would offer.
### 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,12 +5,11 @@
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 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 * `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
* with no users memory usage is ~8.47 MB * with no users memory usage is 8.47 Mb
* saving frequency being set to 0 will disable frequency saving and only save on close * Saving frequency (a runtime argument) being set to 0 will disable frequency saving and only save on close
* make backups of your save files!
## Docker & Ansible ## Docker
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
@ -64,18 +63,18 @@ mkdir build
cd build cd build
``` ```
### CMake Variables ### CMake Flags
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 | "config/users.dat" | where the users are saved | `N/A` | `N/A` | | USER_SAVE_LOC | "users.dat" | where the users are saved | `N/A` | `N/A` |
| DROGON_CONFIG_LOC | "config/config.json" | where the config is located | `N/A` | `N/A` | | DROGON_CONFIG_LOC | "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:
``` ```
@ -94,7 +93,6 @@ 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/).
@ -144,16 +142,4 @@ 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,32 +1,24 @@
[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 | support | image | | author | name | v1 | 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) |
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | | | [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) | :heavy_check_mark: | |
| [Sam](https://github.com/STBoyden) | [Market](https://github.com/STBoyden/market-api-2.0) | :heavy_multiplication_x: | |
## Minecraft ## Minecraft
| author | name | support | image | | author | name | v1 | 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) | ⚠ | ![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) | :heavy_check_mark: | ![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 |
| :-----------: | :------------------------------------------------------------- | | :----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Gambling | physical or digital casino. | | Market | a platform to buy and sell items. |
| Shipping | the infastructure to quickly send items across long distances. | | 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. |
| Mod or Plugin | a server-side mod | | Gambling | physical or digital casino. |
| Shipping | the infastructure to quickly send items across long distances. |

View file

@ -1,14 +1,13 @@
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md) [PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
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 | | v1 |
| author | language | | newest CCash supported version | | :-------------------------------------------------------- | :------: | ------------------------------------------------------------------------- | :----------------------: |
| :-------------------------------------------------------- | :--------: | -------------------------------------------------------------------- | :----------------------------: | | [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | :heavy_check_mark: |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | `v2.5.1` | | [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | JS | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | :heavy_multiplication_x: |
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://github.com/STBoyden/ccash-rs) | `v2.5.1` | | [Doggo](https://github.com/FearlessDoggo21) | Python | [CCashPythonClient](https://github.com/FearlessDoggo21/CCashPythonClient) | :heavy_check_mark: |
| [Doggo](https://github.com/ArcNyxx) | Python | [CCashPythonClient](https://github.com/ArcNyxx/ccash_python_client) | `v2.5.1` | | [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://git.stboyden.com/STBoyden/ccash-rs) | :heavy_check_mark: |
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | TypeScript | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | `v1.3.0` |
here is a demo program for the lua API by SpaceCat for example 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,89 +10,115 @@
`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
⚠ - Deprecated endpoint :heavy_check_mark:
: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 | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: | | :------------- | ------------------------------------------------------------------------------ | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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 | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: | | GetBal | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | GetLog | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | VerifyPassword | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | ### Usage endpoint support
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | `v` denoting the API version
| 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 | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------------ | :---------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: | | :------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :---------: | :----------------------------: | :----------------: | :----------------: | :----------------------: | :----------------------: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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 | 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: |
| 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 |
| :------------------ | :----------------: | :----------------: | :----------------: | :----------------: | | :------------------ | :----------------: | :----------------: | :----------------------: | :----------------: |
| AdminGetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :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: |
| AdminVerifyAccount | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | | SetBal | :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: |
| 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 | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------ | :---------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: | | :----------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :----------------------------------------------------------------------------------: | :----------------------: | :----------------------: | :----------------------: | :----------------------: |
| Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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 | 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 | :x: | :x: | :x: | | Help | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: | | Close | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: | | AdminVerifyAccount | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
| ApiProperties | :x: | :x: | :x: | | PruneUsers | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
| 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
* letters * lowercase 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 | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U | | name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------- | :---------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: | | :----------- | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
| 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: | | 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: |
### User Management endpoint errors ### User Management endpoint errors
| name | 400 | 401 | 404 | 406 | 409 | | name | 400 | 401 | 404 | 406 | 409 |
| :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | | :----------- | :----------------------: | :----------------------: | :----------------------: | :----------------: | :----------------------: |
| AddUser | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | AddUser | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | | AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
| DelSelf | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | | DelSelf | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: |
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | | AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_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) | Github Actions, and JS API | | [Luke](https://github.com/LukeeeeBennett) | Docker package, JS API |
| [React](https://github.com/Reactified) | Logo, CC Wallet/Shop/ATM | | [React](https://github.com/Reactified) | Logo, deprecated CCLua API |
| [Doggo](https://github.com/FearlessDoggo21) | HTTP advice, Python API, and C CLI | | [Doggo](https://github.com/FearlessDoggo21) | HTTP suggestions, Python API |
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API | | [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
| [Expand](https://github.com/Expand-sys) | Docker, and Ansible | | [Expand](https://github.com/Expand-sys) | Fixed docker package |
| [Sam](https://github.com/STBoyden) | Rust API | | [Sam](https://github.com/STBoyden) | Rust API |
| Caesay | Restful API advice | | Caesay | Restful API suggestions |

View file

@ -7,23 +7,9 @@ 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> ghcr.io/entiretwix/ccash/ccash:latest docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> expandsys/ccash
``` ```
## 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,12 +4,15 @@
## Performance ## Performance
#### Speed #### Speed
<!-- graphs --> <!-- graphs -->
Capable of processing thousands of requests per second, with little slow down as user size grows to the millions. Capable of processing thousands of requests per second, with no slow down as user size grows to the millions.
#### Lightweight #### Lightweight
<!-- specs --> <!-- specs -->
* Low memory usage at 8 MB baseline, and 139 bytes per new log. Low memory usage at 8 Mb baseline, and 203 bytes per new log.
* Extremely low CPU usage in the single digits of %.
* Small save files at typically a couple kb, easily shareable. Anecdotally I typically expierenced <1% CPU usage.
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.
@ -29,5 +32,3 @@ 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,25 +6,26 @@ 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.
* Some resources are passively reapable (e.g iron or gold), making the generation of currency a larger focus than that of creating value. * There is no central authority minting the currency. Any consumer can introduce more diamonds to the system.
* 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 physical possession based. * Theft is possible; ownership is 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 can proccess thousands of requests per second. 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.
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 and CCash is very lightweight and so will be a tiny proportion of the server's total computation. 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.
**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.
I suggest an admin should manage the instance to lower incentive to manipulate balances. It's suggested an admin should manage the instance to lower incentive to manipulate.

View file

@ -1,12 +0,0 @@
# 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 counterparty = ""; string from = "";
bool receiving = false; string to = "";
uint32 amount = 0; uint32 amount = 0;
timestamp time; timestamp time;
} }

View file

@ -1,24 +1,22 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#include "bank_dom.h" #include "bank_dom.h"
namespace bank_dom { namespace bank_dom {
Transaction::Transaction() Transaction::Transaction()
: counterparty("") : from("")
, receiving(false) , to("")
, amount((uint32_t)0ull) , amount((uint32_t)0ull)
, time((uint64_t)0ull) , time((uint64_t)0ull)
{} {}
Transaction::Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time) Transaction::Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time)
: counterparty(arg_counterparty) : from(arg_from)
, receiving(arg_receiving) , to(arg_to)
, amount(arg_amount) , amount(arg_amount)
, time(arg_time) , time(arg_time)
{} {}
@ -38,8 +36,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(counterparty, other.counterparty); swap(from, other.from);
swap(receiving, other.receiving); swap(to, other.to);
swap(amount, other.amount); swap(amount, other.amount);
swap(time, other.time); swap(time, other.time);
} }
@ -47,8 +45,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 << "counterparty="; stream << "\"" << value.counterparty << "\""; stream << "from="; stream << "\"" << value.from << "\"";
stream << ",receiving="; stream << (value.receiving ? "true" : "false"); stream << ",to="; stream << "\"" << value.to << "\"";
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,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -29,15 +27,15 @@ namespace bank_dom {
struct Transaction struct Transaction
{ {
std::string counterparty; std::string from;
bool receiving; std::string to;
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_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time); Transaction(const std::string& arg_from, const std::string& arg_to, 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;
@ -62,12 +60,10 @@ struct Transaction
} // namespace bank_dom } // namespace bank_dom
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
template <> struct fmt::formatter<bank_dom::Transaction> : ostream_formatter {};
#endif
template<> template<>
struct std::hash<bank_dom::Transaction> struct 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;
@ -79,6 +75,8 @@ struct std::hash<bank_dom::Transaction>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct Logs struct Logs
@ -113,12 +111,10 @@ struct Logs
} // namespace bank_dom } // namespace bank_dom
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
template <> struct fmt::formatter<bank_dom::Logs> : ostream_formatter {};
#endif
template<> template<>
struct std::hash<bank_dom::Logs> struct 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;
@ -130,6 +126,8 @@ struct std::hash<bank_dom::Logs>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct User struct User
@ -166,12 +164,10 @@ struct User
} // namespace bank_dom } // namespace bank_dom
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
template <> struct fmt::formatter<bank_dom::User> : ostream_formatter {};
#endif
template<> template<>
struct std::hash<bank_dom::User> struct 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;
@ -183,6 +179,8 @@ struct std::hash<bank_dom::User>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
struct Global struct Global
@ -218,12 +216,10 @@ struct Global
} // namespace bank_dom } // namespace bank_dom
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
template <> struct fmt::formatter<bank_dom::Global> : ostream_formatter {};
#endif
template<> template<>
struct std::hash<bank_dom::Global> struct 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;
@ -235,6 +231,8 @@ struct std::hash<bank_dom::Global>
} }
}; };
} // namespace std
namespace bank_dom { namespace bank_dom {
} // namespace bank_dom } // namespace bank_dom

View file

@ -1,17 +1,15 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.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)
, counterparty(buffer, 0) , from(buffer, 0)
, receiving(buffer, 0) , to(buffer, 0)
, amount(buffer, 0) , amount(buffer, 0)
, time(buffer, 0) , time(buffer, 0)
{} {}
@ -19,8 +17,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
+ counterparty.fbe_allocation_size(fbe_value.counterparty) + from.fbe_allocation_size(fbe_value.from)
+ receiving.fbe_allocation_size(fbe_value.receiving) + to.fbe_allocation_size(fbe_value.to)
+ 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)
; ;
@ -40,14 +38,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;
counterparty.fbe_offset(fbe_current_offset); from.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.verify(); fbe_field_size = from.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;
receiving.fbe_offset(fbe_current_offset); to.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.verify(); fbe_field_size = to.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;
@ -81,13 +79,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;
counterparty.fbe_offset(fbe_current_offset); from.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.get(fbe_value.counterparty); fbe_field_size = from.get(fbe_value.from);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
receiving.fbe_offset(fbe_current_offset); to.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.get(fbe_value.receiving); fbe_field_size = to.get(fbe_value.to);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
@ -118,13 +116,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;
counterparty.fbe_offset(fbe_current_offset); from.fbe_offset(fbe_current_offset);
fbe_field_size = counterparty.set(fbe_value.counterparty); fbe_field_size = from.set(fbe_value.from);
fbe_current_offset += fbe_field_size; fbe_current_offset += fbe_field_size;
fbe_current_size += fbe_field_size; fbe_current_size += fbe_field_size;
receiving.fbe_offset(fbe_current_offset); to.fbe_offset(fbe_current_offset);
fbe_field_size = receiving.set(fbe_value.receiving); fbe_field_size = to.set(fbe_value.to);
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,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -62,8 +60,8 @@ private:
mutable size_t _offset; mutable size_t _offset;
public: public:
FinalModel<std::string> counterparty; FinalModel<std::string> from;
FinalModel<bool> receiving; FinalModel<std::string> to;
FinalModel<uint32_t> amount; FinalModel<uint32_t> amount;
FinalModel<uint64_t> time; FinalModel<uint64_t> time;
}; };

View file

@ -1,26 +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
// FBE version: 1.14.1.0 // Version: 1.7.0.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)
, counterparty(buffer, 4 + 4) , from(buffer, 4 + 4)
, receiving(buffer, counterparty.fbe_offset() + counterparty.fbe_size()) , to(buffer, from.fbe_offset() + from.fbe_size())
, amount(buffer, receiving.fbe_offset() + receiving.fbe_size()) , amount(buffer, to.fbe_offset() + to.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
+ counterparty.fbe_size() + from.fbe_size()
+ receiving.fbe_size() + to.fbe_size()
+ amount.fbe_size() + amount.fbe_size()
+ time.fbe_size() + time.fbe_size()
; ;
@ -39,8 +37,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()
+ counterparty.fbe_extra() + from.fbe_extra()
+ receiving.fbe_extra() + to.fbe_extra()
+ amount.fbe_extra() + amount.fbe_extra()
+ time.fbe_extra() + time.fbe_extra()
; ;
@ -77,17 +75,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 + counterparty.fbe_size()) > fbe_struct_size) if ((fbe_current_size + from.fbe_size()) > fbe_struct_size)
return true; return true;
if (!counterparty.verify()) if (!from.verify())
return false; return false;
fbe_current_size += counterparty.fbe_size(); fbe_current_size += from.fbe_size();
if ((fbe_current_size + receiving.fbe_size()) > fbe_struct_size) if ((fbe_current_size + to.fbe_size()) > fbe_struct_size)
return true; return true;
if (!receiving.verify()) if (!to.verify())
return false; return false;
fbe_current_size += receiving.fbe_size(); fbe_current_size += to.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;
@ -143,17 +141,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 + counterparty.fbe_size()) <= fbe_struct_size) if ((fbe_current_size + from.fbe_size()) <= fbe_struct_size)
counterparty.get(fbe_value.counterparty, ""); from.get(fbe_value.from, "");
else else
fbe_value.counterparty = ""; fbe_value.from = "";
fbe_current_size += counterparty.fbe_size(); fbe_current_size += from.fbe_size();
if ((fbe_current_size + receiving.fbe_size()) <= fbe_struct_size) if ((fbe_current_size + to.fbe_size()) <= fbe_struct_size)
receiving.get(fbe_value.receiving, false); to.get(fbe_value.to, "");
else else
fbe_value.receiving = false; fbe_value.to = "";
fbe_current_size += receiving.fbe_size(); fbe_current_size += to.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);
@ -205,8 +203,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
{ {
counterparty.set(fbe_value.counterparty); from.set(fbe_value.from);
receiving.set(fbe_value.receiving); to.set(fbe_value.to);
amount.set(fbe_value.amount); amount.set(fbe_value.amount);
time.set(fbe_value.time); time.set(fbe_value.time);
} }

View file

@ -1,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -74,8 +72,8 @@ private:
size_t _offset; size_t _offset;
public: public:
FieldModel<std::string> counterparty; FieldModel<std::string> from;
FieldModel<bool> receiving; FieldModel<std::string> to;
FieldModel<uint32_t> amount; FieldModel<uint32_t> amount;
FieldModel<uint64_t> time; FieldModel<uint64_t> time;
}; };

View file

@ -1,24 +1,10 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.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,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once
@ -43,6 +41,7 @@
#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
@ -322,20 +321,10 @@ private:
} // namespace FBE } // namespace FBE
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
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 std::hash<FBE::decimal_t> struct 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;
@ -348,6 +337,8 @@ struct std::hash<FBE::decimal_t>
} }
}; };
} // namespace std
namespace FBE { namespace FBE {
// Register a new enum-based flags macro // Register a new enum-based flags macro
@ -539,20 +530,10 @@ private:
} // namespace FBE } // namespace FBE
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000) namespace std {
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 std::hash<FBE::uuid_t> struct 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;
@ -567,6 +548,8 @@ struct std::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,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#include "fbe_final_models.h" #include "fbe_final_models.h"

View file

@ -1,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once

View file

@ -1,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
namespace FBE { namespace FBE {
@ -538,8 +536,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(); TKey key;
TValue value = TValue(); TValue value;
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);
@ -570,8 +568,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(); TKey key;
TValue value = TValue(); TValue value;
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,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#include "fbe_models.h" #include "fbe_models.h"

View file

@ -1,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
#pragma once #pragma once

View file

@ -1,9 +1,7 @@
//------------------------------------------------------------------------------
// 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
// FBE version: 1.14.1.0 // Version: 1.7.0.0
//------------------------------------------------------------------------------
namespace FBE { namespace FBE {
@ -620,8 +618,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(); TKey key;
TValue value = TValue(); TValue value;
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);
@ -642,8 +640,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(); TKey key;
TValue value = TValue(); TValue value;
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 use user iterators //must grab as unique if the operation is gonna user iterators
static std::shared_mutex iter_lock; static std::shared_mutex iter_lock;
public: public:
@ -43,22 +43,16 @@ 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, int64_t amount) noexcept; static BankResponse SetBal(const std::string &name, uint32_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,25 +11,21 @@ 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 AdminGetLogs(req_args, const std::string& name); static void ChangePassword(req_args);
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);
@ -37,55 +33,41 @@ 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::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>"); METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, 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)
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, "/help", Get, Options); METHOD_ADD(api::Help, "/v1/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,22 +10,12 @@ 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;
#if USE_DEPRECATED_ENDPOINTS std::string GetLogs() noexcept;
std::string GetLogs(const std::string& name) noexcept; void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) 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,11 +1,6 @@
#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,11 +5,10 @@
struct Transaction struct Transaction
{ {
std::string counterparty = ""; std::string from = "", to = "";
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 &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept; Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time) noexcept;
}; };

View file

@ -34,48 +34,46 @@ 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\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n"; std::cout << "User save file generated\nUsage: sudo ./bank <admin account> <saving frequency in minutes>\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> [daemon flag {default: false}]\n"; std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes>\n";
return -1; return 0;
} }
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 -1; return 0;
} }
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
std::cout std::cout
<< "\nAPI : v2.6.1\n" << "\nAPI Version : " << API_VERSION
<< "\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled") << "\n\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() + saving_freq << "\n\nThreads : " << get_nprocs() + 1
<< "\nMulti threading : enabled"; << "\nMulti threading : enabled";
#else #else
<< "\n\nThreads : " << 1 + saving_freq << "\n\nThreads : " << 2
<< "\nMulti threading : disabled"; << "\nMulti threading : disabled";
#endif #endif
//Loading users from users.dat //Loading users from users.json
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 * (75 + sizeof(Transaction) + max_name_size)) / 1048576 << "MB" //75:cached response per log(heap), sizeof(Transaction), max_name_size:counterparty(heap) << "\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 " << Bank::SumBal() << " C$H" << "\nLoaded " << Bank::SumBal() << " C$H"
<< std::endl; //flushing before EventLoop << std::endl; //flushing before EventLoop
@ -90,24 +88,19 @@ 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" << Bank::Save(); std::cout << "Saving " << std::time(0) << "...\n"
} << 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 >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
{ {
return false; return false;
} }
@ -85,14 +85,11 @@ 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, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; })) if (!Bank::users.modify_if(name, [&res](User &u) { res = {k200OK, u.log.GetLogs()}; }))
{ {
return {k404NotFound, "\"User not found\""}; return {k404NotFound, "\"User not found\""};
} }
@ -102,44 +99,6 @@ 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)
@ -164,7 +123,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\""};
@ -173,7 +132,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(b_name, false, amount, current_time); a.log.AddTrans(a_name, b_name, amount, current_time);
#endif #endif
res = {k200OK, std::to_string(a.balance)}; res = {k200OK, std::to_string(a.balance)};
} }
@ -186,7 +145,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, true, amount, current_time); b.log.AddTrans(a_name, b_name, 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; });
@ -201,20 +160,15 @@ 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, int64_t amount) noexcept BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept
{ {
if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) { if (ValidUsername(name) && Bank::users.modify_if(name, [amount](User &u) { u.balance = amount; }))
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
@ -231,13 +185,7 @@ 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) { if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, amount](User &u) { bal = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); }))
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
@ -264,26 +212,15 @@ 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,10 +1,12 @@
#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", "*")
thread_local ondemand::parser parser; static 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;
@ -22,13 +24,13 @@ 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
@ -40,44 +42,6 @@ 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;
@ -116,7 +80,7 @@ void api::ChangePassword(req_args)
else else
{ {
std::string_view pass; std::string_view pass;
if (doc["pass"].get(pass)) if (doc["time"].get(pass))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
} }
@ -140,7 +104,7 @@ void api::AdminChangePassword(req_args)
else else
{ {
std::string_view name, pass; std::string_view name, pass;
if (doc["name"].get(name) || doc["pass"].get(pass)) if (doc["name"].get(name) || doc["time"].get(pass))
{ {
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""}; res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
} }
@ -242,7 +206,15 @@ void api::AdminVerifyAccount(req_args)
} }
void api::ApiProperties(req_args) void api::ApiProperties(req_args)
{ {
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") + '}'; 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);
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;
@ -258,9 +230,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)\""};
@ -270,6 +242,7 @@ 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)\""};
@ -330,7 +303,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["pass"].get(pass) || (amount > std::numeric_limits<uint32_t>::max())) if (doc["name"].get(name) || doc["amount"].get(amount) || doc["time"].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)\""};
} }
@ -371,3 +344,4 @@ void api::AdminDelUser(req_args)
} }
RESPONSE_PARSE(std::move(res)); RESPONSE_PARSE(std::move(res));
} }
#endif

View file

@ -1,27 +1,22 @@
#include "log.h" #include "log.h"
void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept void Log::AddTrans(const std::string &from, const std::string &to, 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_front(); data.pop_back();
} }
data.emplace_back(counterparty_str, receiving, amount, time); data.emplace_back(from, to, amount, time);
} }
#if USE_DEPRECATED_ENDPOINTS std::string Log::GetLogs() noexcept
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 = ((57 + (2 * max_name_size)) * data.size()) + 1; size_t predicted_size = ((59 + (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);
@ -29,140 +24,18 @@ std::string Log::GetLogs(const std::string& name) 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\":\""; //7 log_snapshot += "{\"to\":\""; //8
log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size? log_snapshot += data[i].to; //max_name_size?
log_snapshot += "\",\"from\":\""; //10 log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size? log_snapshot += data[i].from; //max_name_size?
log_snapshot += "\",\"amount\":"; //11 log_snapshot += "\",\"amount\":"; //12
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 &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {} 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) {}

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.counterparty, temp.receiving, temp.amount, temp.time); log.data.emplace_front(temp.from, temp.to, 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.counterparty, t.receiving, t.amount, t.time); save_log.data.emplace_back(t.from, t.to, 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 >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
{ {
return false; return false;
} }