mirror of
https://github.com/Expand-sys/CCash
synced 2025-12-17 00:22:14 +11:00
Compare commits
153 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f85e13f11 | ||
|
|
7fcb761aa2 | ||
|
|
caf1d65e16 | ||
|
|
a61a590f3a | ||
|
|
32f5f2a2be | ||
|
|
a98b84955c | ||
|
|
c970b6a42f | ||
|
|
f2da8cdbc2 | ||
|
|
af551ef8b4 | ||
|
|
511aa76795 | ||
|
|
eea9c4b566 | ||
|
|
cb5d12d4dc | ||
|
|
01aedef7a3 | ||
|
|
6ddcf08797 | ||
|
|
4a41cb1ef4 | ||
|
|
dda98f346e | ||
|
|
2419641cd0 | ||
|
|
6dad3ed0af | ||
|
|
88458de0f0 | ||
|
|
47649d6ccd | ||
|
|
370107e3f9 | ||
|
|
8fea062a3f | ||
|
|
779ab90b8f | ||
|
|
0d346b820f | ||
|
|
c659c9b7bd | ||
|
|
5e996b2705 | ||
|
|
7e1954d651 | ||
|
|
ad3bb2c13b | ||
|
|
b74510a113 | ||
|
|
4aa55486c9 | ||
|
|
e413c089dc | ||
|
|
a195e8c5a2 | ||
|
|
396b676ee5 | ||
|
|
dce87bbcfa | ||
|
|
705a746a3c | ||
|
|
6e6d722f9f | ||
|
|
70ac88e894 | ||
|
|
6f1bd193d5 | ||
|
|
69a2f81454 | ||
|
|
113f42a399 | ||
|
|
3629b78e38 | ||
|
|
282bd5e423 | ||
|
|
b656bb7e43 | ||
|
|
3b46c97d0a | ||
|
|
3e73d08227 | ||
|
|
82e3a6384c | ||
|
|
d303016124 | ||
|
|
66b21332b3 | ||
|
|
34039f9fcf | ||
|
|
ce65a4387c | ||
|
|
95c2d47216 | ||
|
|
8696c5d870 | ||
|
|
dbe755da2b | ||
|
|
24665641b4 | ||
|
|
026d2b8493 | ||
|
|
99f47dc6ed | ||
|
|
d8e88ec375 | ||
|
|
8ff1fddf7a | ||
|
|
07b9e20e31 | ||
|
|
83455a0510 | ||
|
|
cc103c7298 | ||
|
|
10c3c6a536 | ||
|
|
21fd1c94e4 | ||
|
|
b69092d732 | ||
|
|
472a9222fc | ||
|
|
878a71f310 | ||
|
|
411d1996c7 | ||
|
|
722f8d0f48 | ||
|
|
aefdb4ce9b | ||
|
|
76388c6423 | ||
|
|
ff0dfc8a93 | ||
|
|
5e253e42d9 | ||
|
|
d63be0ec73 | ||
|
|
4ca1bbe6eb | ||
|
|
54acbf8cc6 | ||
|
|
2c62c89b47 | ||
|
|
37b110d36f | ||
|
|
8e44a3d446 | ||
|
|
e20ac4cebc | ||
|
|
19b6acc48f | ||
|
|
ed0d5c8231 | ||
|
|
6d9c6d6c1c | ||
|
|
04fe7376ec | ||
|
|
292b73001e | ||
|
|
c8791ec7ce | ||
|
|
a308f830c0 | ||
|
|
a49a1730f7 | ||
|
|
0b7de8b905 | ||
|
|
b674a6dded | ||
|
|
49b5b7d35d | ||
|
|
f9aa33afac | ||
|
|
da65fb678a | ||
|
|
7850c721e5 | ||
|
|
09422995e8 | ||
|
|
d5f5b41e20 | ||
|
|
7d4a564513 | ||
|
|
a68e86b216 | ||
|
|
a9e3ca1665 | ||
|
|
f6d8673045 | ||
|
|
206698697b | ||
|
|
f1b03ecb41 | ||
|
|
94c2cb1f65 | ||
|
|
7c31b4d680 | ||
|
|
b874af86af | ||
|
|
73a80de08e | ||
|
|
35c50ac0f4 | ||
|
|
4892ec2655 | ||
|
|
d46fe68559 | ||
|
|
52677f0576 | ||
|
|
d2f0989a15 | ||
|
|
ecb602d6f2 | ||
|
|
a068502643 | ||
|
|
49816dc18c | ||
|
|
e100444042 | ||
|
|
4fd3eb2bd8 | ||
|
|
cf4ba5ccfa | ||
|
|
244ca2561c | ||
|
|
b584f5b4d5 | ||
|
|
ab27971d8e | ||
|
|
7387156d15 | ||
|
|
47d544070b | ||
|
|
1f983322a1 | ||
|
|
5a754a567c | ||
|
|
83f149677d | ||
|
|
61134740f0 | ||
|
|
78b62092b3 | ||
|
|
1b2c763f0b | ||
|
|
a8b7defb36 | ||
|
|
1498d3d028 | ||
|
|
dffd20511d | ||
|
|
6c8ebfa57c | ||
|
|
decfd83931 | ||
|
|
89448a4b12 | ||
|
|
2fa6a7a743 | ||
|
|
d56599f49a | ||
|
|
df21ce4131 | ||
|
|
dcbb65ab6f | ||
|
|
5999a00d68 | ||
|
|
e04cd1af04 | ||
|
|
90add46113 | ||
|
|
c0b02fa7aa | ||
|
|
9761aa93b5 | ||
|
|
e536bb94fb | ||
|
|
279481532e | ||
|
|
0fc044fdda | ||
|
|
5e71954391 | ||
|
|
c9f7e103ce | ||
|
|
6cf167b42d | ||
|
|
3f08055dd0 | ||
|
|
1776eaea2f | ||
|
|
50c88aa32f | ||
|
|
46c97fd813 | ||
|
|
e8576b76f8 |
44 changed files with 812 additions and 476 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
.vscode
|
||||
build
|
||||
ccash_config.hpp
|
||||
deployment/.yamllint
|
||||
config
|
||||
|
|
@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
|||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp )
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
src/bank_api.cpp
|
||||
|
|
@ -38,15 +38,15 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
)
|
||||
|
||||
if(DEFINED USER_SAVE_LOC)
|
||||
set(USER_SAVE ${USER_SAVE_LOC})
|
||||
set(USER_SAVE "\"${USER_SAVE_LOC}\"")
|
||||
else()
|
||||
set(USER_SAVE "\"users.dat\"")
|
||||
set(USER_SAVE "\"../config/users.dat\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED DROGON_CONFIG_LOC)
|
||||
set(DROGON_CONFIG ${DROGON_CONFIG_LOC})
|
||||
set(DROGON_CONFIG "\"${DROGON_CONFIG_LOC}\"")
|
||||
else()
|
||||
set(DROGON_CONFIG "\"config.json\"")
|
||||
set(DROGON_CONFIG "\"../config/config.json\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED MAX_LOG_SIZE)
|
||||
|
|
@ -75,12 +75,18 @@ endif()
|
|||
|
||||
if(DEFINED RETURN_ON_DEL_NAME)
|
||||
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()
|
||||
set(RETURN_ON_DEL_VAL false)
|
||||
set(RETURN_ON_DEL_NAME_VAL "\"\"")
|
||||
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)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
|
|
|
|||
16
Dockerfile
16
Dockerfile
|
|
@ -1,21 +1,21 @@
|
|||
FROM alpine:3.11
|
||||
FROM alpine:latest
|
||||
|
||||
WORKDIR /
|
||||
|
||||
RUN apk update && apk add git cmake g++ make protobuf jsoncpp-dev openssl libressl-dev zlib-dev util-linux-dev libtool autoconf automake python3
|
||||
RUN apk update && apk add bash git cmake g++ make protobuf jsoncpp-dev openssl libressl-dev zlib-dev util-linux-dev libtool autoconf automake python3
|
||||
|
||||
RUN git clone --recurse-submodules https://github.com/EntireTwix/CCash.git
|
||||
WORKDIR /CCash/third_party/base64/
|
||||
RUN AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o
|
||||
RUN mkdir /CCash/build
|
||||
WORKDIR /CCash/build
|
||||
RUN cmake -DDROGON_CONFIG_LOC=\"\/CCash\/config\/config.json\" -DUSER_SAVE_LOC=\"\/CCash\/config\/users.json\" ..
|
||||
RUN cmake -DDROGON_CONFIG_LOC="/CCash/config/config.json" -DUSER_SAVE_LOC="/CCash/config/users.dat" ..
|
||||
RUN make -j$(nproc)
|
||||
|
||||
ARG ADMIN_A=admin
|
||||
ARG SAVE_FREQ=2
|
||||
|
||||
RUN ["chmod", "+x", "/CCash/config/ssl.sh"]
|
||||
|
||||
RUN ["sh", "-c", "/CCash/config/ssl.sh && /CCash/build/bank"]
|
||||
CMD ["sh", "-c", "/CCash/config/ssl.sh && /CCash/build/bank ${ADMIN_A} ${SAVE_FREQ}"]
|
||||
WORKDIR /
|
||||
RUN sed -i 's/\r$//' /CCash/config/ssl.sh && \
|
||||
chmod +x /CCash/config/ssl.sh
|
||||
RUN /CCash/build/bank
|
||||
CMD /CCash/config/ssl.sh && /CCash/build/bank ${ADMIN_A} ${SAVE_FREQ}
|
||||
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
* [problem/solution](docs/idea.md)
|
||||
* connected services
|
||||
* how to contribute
|
||||
* how to create
|
||||
* [explanation](docs/connected_services/how_to/explanation.md)
|
||||
* [language APIs](docs/connected_services/how_to/APIs.md)
|
||||
* [API endpoints](docs/connected_services/how_to/endpoints.md)
|
||||
* [API implementations](docs/connected_services/how_to/APIs.md)
|
||||
* [the API](docs/connected_services/how_to/endpoints.md)
|
||||
* [existing services](docs/connected_services/existing_services.md)
|
||||
* features
|
||||
* [user side](docs/features/user_side.md)
|
||||
* [implementation](docs/features/implementation.md)
|
||||
* [building](docs/building.md)
|
||||
* [FAQ](docs/FAQ.md)
|
||||
* [Liberapay](https://en.liberapay.com/EntireTwix/) if you wanna support this and/or future projects
|
||||
|
||||
* [Versions](docs/versioning.md)
|
||||
|
|
|
|||
|
|
@ -61,10 +61,11 @@ using namespace std::chrono;
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
for (size_t i = 0; i < 10000; ++i)
|
||||
for (size_t i = 100; i < 10100; ++i)
|
||||
{
|
||||
Bank::AddUser(std::to_string(i), 0, "root");
|
||||
}
|
||||
std::cout << "added " << Bank::NumOfUsers() << " users\n";
|
||||
Bank::AddUser("twix", 0, "root");
|
||||
Bank::AddUser("jolly", 0, "root");
|
||||
Bank::admin_account = "twix";
|
||||
|
|
@ -89,25 +90,16 @@ int main(int argc, char **argv)
|
|||
Op(Bank::VerifyPassword("twix", "root"), "verify pass: ", 1000000);
|
||||
Op(Bank::ChangePassword("twix", "root"), "change pass: ", 1000000);
|
||||
#if MAX_LOG_SIZE > 0
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
Op(Bank::GetLogs("twix"), "get logs init: ", 1);
|
||||
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
|
||||
Op(Bank::PruneUsers(0, 0), "prune users: ", 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Setting to 0 does not compile logging (useful for if disk/memory is very valuable)
|
||||
#define MAX_LOG_SIZE @MAX_LOG_SIZE_VAL@
|
||||
|
||||
//default to minecraft usernames
|
||||
// Default to minecraft usernames
|
||||
constexpr unsigned min_name_size = 3;
|
||||
constexpr unsigned max_name_size = 16;
|
||||
|
||||
|
|
@ -28,15 +28,8 @@ if false, when frequency is hit save
|
|||
*/
|
||||
#define CONSERVATIVE_DISK_SAVE @CONSERVATIVE_DISK_SAVE_VAL@
|
||||
|
||||
/*
|
||||
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 ADD_USER_OPEN @ADD_USER_OPEN_VAL@
|
||||
|
||||
#define USE_DEPRECATED_ENDPOINTS @USE_DEPRECATED_ENDPOINTS_VAL@
|
||||
BIN
config/users.dat
Normal file
BIN
config/users.dat
Normal file
Binary file not shown.
35
docs/FAQ.md
35
docs/FAQ.md
|
|
@ -1,23 +1,20 @@
|
|||
[PREVIOUS PAGE](building.md)
|
||||
|
||||
#### Q : How do I setup a CCash instance
|
||||
#### A : You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package.
|
||||
|
||||
#### Q : Why is my username invalid
|
||||
#### A : Usernames are restricted by minecraft's requirements
|
||||
* lowercase letters
|
||||
### 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.
|
||||
### Why is my username invalid
|
||||
Usernames are restricted by minecraft's requirements
|
||||
* letters
|
||||
* numbers
|
||||
* _
|
||||
* Length must be atleast 3 and at most 16 characters.
|
||||
|
||||
#### Q : Is this a crypto like krist?
|
||||
#### A : CCash isn't a crypto, the economy you decide to implement is entirely up to you.
|
||||
|
||||
#### Q : My instance is taking up too much RAM
|
||||
#### A : If your memory usage is too high I would reduce log size.
|
||||
|
||||
#### 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. If when the frequency of saving arrives its highly likely changes have occurred (say by high activity or low save frequency) then disabling conservative saving will marginally increase performance.
|
||||
|
||||
#### Q : My instance is taking up too much disk spac
|
||||
#### A : Use the purge users endpoint to delete old or superfluous accounts or reducing log size will reduce disk space.
|
||||
* 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?
|
||||
Because this usecase requires none of the features a database would offer.
|
||||
### People are making too many accounts maliciously to fill up space on my server!
|
||||
Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
|
||||
### My instance is taking up too much storage or RAM
|
||||
Reduce log size and/or use the prune users endpoint to remove dead accounts.
|
||||
### Why not use an economy mod
|
||||
Speed of operations, CCash being external to MC (and so compatible with any version/configuration), and the API are the main advantages to an economy mod.
|
||||
|
|
@ -4,12 +4,13 @@
|
|||
## Advice
|
||||
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`
|
||||
* if your server is sufficiently active as so that each save frequency saving is highly likely then `CONSERVATIVE_DISK_SAVE` should be toggled to `false`
|
||||
* `MAX_LOG_SIZE` should be adjusted as it takes up the most memory usage/storage of the ledger's features at ~203 bytes in memory and ~104 bytes in disk at default settings, so 5165 logs per Mb of RAM. Setting to 0 will disable logs
|
||||
* with no users memory usage is 8.47 Mb
|
||||
* Saving frequency (a runtime argument) being set to 0 will disable frequency saving and only save on close
|
||||
* 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
|
||||
* with no users memory usage is ~8.47 MB
|
||||
* saving frequency being set to 0 will disable frequency saving and only save on close
|
||||
* make backups of your save files!
|
||||
|
||||
## Docker
|
||||
## Docker & Ansible
|
||||
If you want to use the docker package, deploy information can be found [here](deploy.md)
|
||||
|
||||
## Drogon Depedencies
|
||||
|
|
@ -61,21 +62,20 @@ AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse
|
|||
cd ../..
|
||||
mkdir build
|
||||
cd build
|
||||
cp ../config/config.json config.json
|
||||
```
|
||||
|
||||
### CMake Flags
|
||||
### CMake Variables
|
||||
there are multiple flags responsible configuring CCash:
|
||||
| name | default | description | pros | cons |
|
||||
| :--------------------- | :-----------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
|
||||
| USER_SAVE_LOC | "users.dat" | where the users are saved | `N/A` | `N/A` |
|
||||
| DROGON_CONFIG_LOC | "config.json" | where the config is located | `N/A` | `N/A` |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
| name | default | description | pros | cons |
|
||||
| :----------------------- | :------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
|
||||
| USER_SAVE_LOC | "config/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` |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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:
|
||||
```
|
||||
|
|
@ -92,8 +92,9 @@ lastly type in
|
|||
```
|
||||
cmake <flags of your choice or none> ..
|
||||
make -j<threads>
|
||||
./bank
|
||||
sudo ./bank
|
||||
```
|
||||
the last command generates a blank save file in your defined location.
|
||||
|
||||
## Certs
|
||||
make sure to edit `config.json` adding the certificate location if you're using HTTPS, I personally use [certbot](https://certbot.eff.org/).
|
||||
|
|
@ -143,4 +144,16 @@ leaving
|
|||
]
|
||||
}
|
||||
```
|
||||
**it is Highly recommened you secure your server**
|
||||
|
||||
## Usage
|
||||
You can now run the program from the build location. For example
|
||||
```
|
||||
sudo ./bank admin 5
|
||||
```
|
||||
in this example CCash will be launched with the admin account named `"admin"`, and a saving frequency of every `5` minutes; without daemon being given its default is `false`.
|
||||
|
||||
Another example
|
||||
```
|
||||
sudo ./bank Kevin 0 true
|
||||
```
|
||||
in this example CCash will be launched with the admin account named `"Kevin"`, and a saving frequency of `0` meaning the server will only save when closed; daemon is set to `true` and so will be launched in the background.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,32 @@
|
|||
[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
|
||||
| author | name | v1 |
|
||||
| :------------------------------------------ | ----------------------------------------------------------- | :----------------------: |
|
||||
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: |
|
||||
| [Expand](https://github.com/Expand-sys) | [Discord Bot](https://github.com/Expand-sys/ccashbot) | :heavy_check_mark: |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | [CCash CLI](https://github.com/FearlessDoggo21/ccash_cmd) | :heavy_check_mark: |
|
||||
| [Sam](https://github.com/STBoyden) | [Market](https://github.com/STBoyden/market-api-2.0) | :heavy_multiplication_x: |
|
||||
| author | name | support | image |
|
||||
| :-------------------------------------- | ----------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
|
||||
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: |  | |
|
||||
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | |
|
||||
|
||||
## Minecraft
|
||||
| author | name | v1 |
|
||||
| :------------------------------------------ | --------------------------------------------------------------------------- | :----------------: |
|
||||
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: |
|
||||
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | :heavy_check_mark: |
|
||||
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: |
|
||||
| author | name | support | image |
|
||||
| :------------------------------------------ | ---------------------------------------------------------------------------------------- | :----------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: |  |
|
||||
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ |  |
|
||||
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: |  |
|
||||
| [Reactified](https://github.com/Reactified) | [Chunk Loader Shop](https://github.com/Reactified/rpm/tree/main/packages/forceload-shop) | :heavy_check_mark: |   |
|
||||
| [STBoyden](https://github.com/STBoyden) | [Commodities Exchange](https://github.com/STBoyden/ccash-market) | :hammer: | |
|
||||
|
||||
|
||||
## Desired
|
||||
| idea | description |
|
||||
| :-----------: | :------------------------------------------------------------- |
|
||||
| Gambling | physical or digital casino. |
|
||||
| Shipping | the infastructure to quickly send items across long distances. |
|
||||
| Mod or Plugin | a server-side mod |
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
[PREVIOUS PAGE](explanation.md) | [NEXT PAGE](endpoints.md)
|
||||
|
||||
| author | language | | v1 |
|
||||
| :-------------------------------------------------------- | :------: | ------------------------------------------------------------------------- | :----------------------: |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | :heavy_check_mark: |
|
||||
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | JS | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | :heavy_multiplication_x: |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | Python | [CCashPythonClient](https://github.com/FearlessDoggo21/CCashPythonClient) | :heavy_check_mark: |
|
||||
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://git.stboyden.com/STBoyden/ccash-rs) | :heavy_check_mark: |
|
||||
CCash is backwards compatible, so even if a language API does not support the newester version it can still call the old endpoints. Only when the major version increments are deprecated features made defunct (e.g `v1.0.0` -> `v2.0.0`), check the [endpoint docs](endpoints.md) to avoid using deprecated endpoints. For more information about versioning check out [versioning docs](../../versioning.md).
|
||||
| author | language | | newest CCash supported version |
|
||||
| :-------------------------------------------------------- | :--------: | -------------------------------------------------------------------- | :----------------------------: |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua | [CatsCCashLuaApi](https://github.com/SpaceCat-Chan/CatsCCashLuaApi) | `v2.5.1` |
|
||||
| [Sam](https://github.com/STBoyden) | Rust | [ccash rs](https://github.com/STBoyden/ccash-rs) | `v2.5.1` |
|
||||
| [Doggo](https://github.com/ArcNyxx) | Python | [CCashPythonClient](https://github.com/ArcNyxx/ccash_python_client) | `v2.5.1` |
|
||||
| [Luke](https://github.com/LukeeeeBennett/ccash-client-js) | TypeScript | [ccash client js](https://github.com/LukeeeeBennett/ccash-client-js) | `v1.3.0` |
|
||||
|
||||
for example here is a demo program for the lua API by SpaceCat
|
||||
here is a demo program for the lua API by SpaceCat
|
||||
|
||||
```lua
|
||||
local ccash = require("ccash.api")
|
||||
|
|
|
|||
|
|
@ -10,115 +10,89 @@
|
|||
|
||||
`A` - Admin, same as `U` but in addition requires username supplied be equal to the admin account username
|
||||
|
||||
:heavy_check_mark:
|
||||
:heavy_multiplication_x:
|
||||
⚠ - Deprecated endpoint
|
||||
|
||||
:no_entry: - Defunct endpoint
|
||||
|
||||
## all error responses have JSON string along with them to describe
|
||||
|
||||
### Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------- | ------------------------------------------------------------------------------ | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| GetBal | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
| name | last change | 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: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
| GetLogsRange | `v2.6.1` | retrieves the logs of a given user, where `{start}` is the 0-indexed first log and `{length}` is the number of logs after that index. | `N/A` | api/v1/user/log_range | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| SendFunds | `v2.3.0` | sends funds from the authenticated user to the user `"name"` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ChangePassword | `v2.3.0` | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| VerifyPassword | `v2.3.0` | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
|
||||
### Usage enpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------- | :----------------------: | :----------------------: | :----------------------: | :----------------: |
|
||||
| GetBal | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLog | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| SendFunds | :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: |
|
||||
|
||||
### Usage endpoint support
|
||||
`v` denoting the API version
|
||||
| name | v1 |
|
||||
| :------------- | :----------------: |
|
||||
| GetBal | :heavy_check_mark: |
|
||||
| GetLog | :heavy_check_mark: |
|
||||
| SendFunds | :heavy_check_mark: |
|
||||
| VerifyPassword | :heavy_check_mark: |
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------- | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| GetBal | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
|
||||
### Meta Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :---------: | :----------------------------: | :----------------: | :----------------: | :----------------------: | :----------------------: |
|
||||
| ChangePassword | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
| name | last change | 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: |
|
||||
| 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: |
|
||||
| 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 | `v2.3.0` | sets the balance of a given user `"name"` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| ImpactBal | `v2.3.0` | modifies the user `"name"`'s balance by `"amount"` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
||||
### Meta Usage endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------------ | :----------------: | :----------------: | :----------------------: | :----------------: |
|
||||
| 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: |
|
||||
| SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|
||||
### Meta Usage endpoint support
|
||||
| name | v1 |
|
||||
| :------------------ | :----------------: |
|
||||
| ChangePassword | :heavy_check_mark: |
|
||||
| AdminChangePassword | :heavy_check_mark: |
|
||||
| SetBal | :heavy_check_mark: |
|
||||
| ImpactBal | :heavy_check_mark: |
|
||||
| name | 400 | 401 | 404 | 406 |
|
||||
| :------------------ | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| AdminGetLogs | :x: | :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: |
|
||||
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|
||||
### Sytem Usage endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :----------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :----------------------------------------------------------------------------------: | :----------------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| Help | redirects to GitHub projects Docs | `N/A` | api/v1/help | `GET` | 301 | `N/A` | `N/A` | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| 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 | 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: |
|
||||
| AdminVerifyAccount | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_multiplication_x: |
|
||||
| PruneUsers | 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: |
|
||||
| name | last change | 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: |
|
||||
| Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| Contains | `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: |
|
||||
| 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: |
|
||||
| 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: |
|
||||
|
||||
### System Usage endpoin errors
|
||||
| name | 401 | 404 | 406 |
|
||||
| :----------------- | :----------------------: | :----------------------: | :----------------------: |
|
||||
| Help | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| Close | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminVerifyAccount | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: |
|
||||
| PruneUsers | :heavy_check_mark: | :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: |
|
||||
| name | 401 | 404 | 406 |
|
||||
| :------------ | :----------------: | :----------------: | :----------------: |
|
||||
| Help | :x: | :x: | :x: |
|
||||
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
||||
| ApiProperties | :x: | :x: | :x: |
|
||||
|
||||
### Username Requirements
|
||||
Valid
|
||||
* lowercase letters
|
||||
* letters
|
||||
* numbers
|
||||
* _
|
||||
* Length must be atleast 3 and at most 16 characters.
|
||||
|
||||
### User Management endpoints
|
||||
| name | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
|
||||
| :----------- | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------------: | :----------------------: | :----------------------: |
|
||||
| AddUser | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: |
|
||||
| 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 | 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 | 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: |
|
||||
| name | last change | 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: |
|
||||
| AdminAddUser | `v2.3.0` | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
|
||||
| AdminDelUser | `v2.3.0` | deletes a given user `"name"` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
||||
### User Management endpoint errors
|
||||
| name | 400 | 401 | 404 | 406 | 409 |
|
||||
| :----------- | :----------------------: | :----------------------: | :----------------------: | :----------------: | :----------------------: |
|
||||
| AddUser | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| 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: | :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: |
|
||||
| name | 400 | 401 | 404 | 406 | 409 |
|
||||
| :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| AddUser | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| AdminAddUser | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| DelSelf | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
|
||||
| AdminDelUser | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Contributors
|
||||
| name | work |
|
||||
| :------------------------------------------- | ---------------------------- |
|
||||
| [Luke](https://github.com/LukeeeeBennett) | Docker package, JS API |
|
||||
| [React](https://github.com/Reactified) | Logo, deprecated CCLua API |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | HTTP suggestions, Python API |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
|
||||
| [Expand](https://github.com/Expand-sys) | Fixed docker package |
|
||||
| [Sam](https://github.com/STBoyden) | Rust API |
|
||||
| Caesay | Restful API suggestions |
|
||||
| name | work |
|
||||
| :------------------------------------------- | ---------------------------------- |
|
||||
| [Luke](https://github.com/LukeeeeBennett) | Github Actions, and JS API |
|
||||
| [React](https://github.com/Reactified) | Logo, CC Wallet/Shop/ATM |
|
||||
| [Doggo](https://github.com/FearlessDoggo21) | HTTP advice, Python API, and C CLI |
|
||||
| [SpaceCat](https://github.com/SpaceCat-Chan) | CCLua API |
|
||||
| [Expand](https://github.com/Expand-sys) | Docker, and Ansible |
|
||||
| [Sam](https://github.com/STBoyden) | Rust API |
|
||||
| Caesay | Restful API advice |
|
||||
|
|
@ -7,9 +7,23 @@ A pre-built docker image is supplied in the repos [GitHub Packages](https://gith
|
|||
It can be run with docker like so:
|
||||
|
||||
```
|
||||
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> expandsys/ccash
|
||||
docker run -itp 443:443 -v ccashconfig:/ccash/config -e ADMIN_A=<admin-username> -e SAVE_FREQ=<in minutes> ghcr.io/entiretwix/ccash/ccash:latest
|
||||
```
|
||||
|
||||
## Ansible
|
||||
Additionally CCash can be deployed to any infrastructure able to run Rocky/Alma Linux 8/9 x86_64 virtual or not, we will be eventually updating it to allow it to run on other OS's but for now RHEL is what works.
|
||||
|
||||
As CCash is intended to be run as root, the playbook is run also as root. The playbook also builds CCash from the latest github push, so there may be bugs.
|
||||
|
||||
In order to use the ansible playbook, clone the playbook to any pc with the ability to access the server through SSH and with Ansible installed, edit the inventory file to contain the IP address of the target server and run the following commands:
|
||||
```ansible-galaxy install -r deployment/requirements.yml
|
||||
```ansible-playbook -i deployment/inventory deployment/main.yml -k```
|
||||
When this is complete the server will have ccash installed to the user dir, this is customizable in the vars/default.yml file along with the admin username and save frequency.
|
||||
To start CCash run:
|
||||
```systemctl start ccash```
|
||||
To run ccash at start up run:
|
||||
```systemctl enable ccash```
|
||||
|
||||
## Build
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@
|
|||
## Performance
|
||||
#### Speed
|
||||
<!-- graphs -->
|
||||
Capable of processing thousands of requests per second, with no slow down as user size grows to the millions.
|
||||
|
||||
Capable of processing thousands of requests per second, with little slow down as user size grows to the millions.
|
||||
#### Lightweight
|
||||
<!-- specs -->
|
||||
Low memory usage at 8 Mb baseline, and 203 bytes per new log.
|
||||
|
||||
Anecdotally I typically expierenced <1% CPU usage.
|
||||
|
||||
Small save files at typically a couple kb, easily shareable.
|
||||
* Low memory usage at 8 MB baseline, and 139 bytes per new log.
|
||||
* Extremely low CPU usage in the single digits of %.
|
||||
* Small save files at typically a couple kb, easily shareable.
|
||||
## Accessibility
|
||||
#### Connected Services
|
||||
as explained in earlier docs a ecosystem of connected services allows you many ways to utilize CCash.
|
||||
#### APIs
|
||||
for devs who wanna make more connected services, existing APIs exist in multiple lanaguages enabling faster development/maintenance.
|
||||
#### External
|
||||
its game indepedent meaning you dont have to be in-game to use it.
|
||||
its game indepedent meaning you dont have to be in-game to use it. With support for Docker and Ansible Playbook.
|
||||
## Security
|
||||
#### HTTPS
|
||||
OpenSSL is used to secure the HTTP server.
|
||||
|
|
@ -29,6 +26,8 @@ if the server's save file is compromised the user passwords will not be derivabl
|
|||
#### Logs
|
||||
each transaction is logged and the last `n` logs are stored, if set to 0 logs will be disabled.
|
||||
#### Return On Delete
|
||||
by default this feature is off, but when enabled deleted account's fund 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
|
||||
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.
|
||||
|
|
|
|||
17
docs/idea.md
17
docs/idea.md
|
|
@ -6,26 +6,25 @@ While CCash can be used for anything that can interact with its API I think mine
|
|||
|
||||
The currency model most Minecraft Servers adopt if any, is resource based, usually diamonds. This model is fraught with issues however:
|
||||
|
||||
* The primary issue is minecraft worlds are infinite leading to hyper inflation as everyone accrues more diamonds.
|
||||
* There is no central authority minting the currency. Any consumer can introduce more diamonds to the system.
|
||||
* Some resources are passively reapable, making the generation of currency a larger focus than that of creating products.
|
||||
* 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.
|
||||
* Locality is required for transactions.
|
||||
* Theft is possible; ownership is possession based.
|
||||
* Theft is possible; ownership is physical possession based.
|
||||
|
||||
CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on.
|
||||
CCash solves these issues and adds a level of abstraction. The main philosophy of CCash is to have fast core operations which other services build on, CCash can proccess thousands of requests per second.
|
||||
|
||||
The CCash instance can be external to the game server.
|
||||
The CCash instance can be external to the game server:
|
||||
|
||||

|
||||
|
||||
or on localhost:
|
||||
Or on localhost:
|
||||
|
||||

|
||||
|
||||
Running it local to the game server reduces latency for connected services. Fortunately CCash is sufficiently lightweight as to not impact performance on most setups.
|
||||
Running it local to the game server reduces latency for connected services and CCash is very lightweight and so will be a tiny proportion of the server's total computation.
|
||||
|
||||
**DISCLAIMER: ComputerCraft requires you add `127.0.0.1` to its config section `allowed_domains` if you're interacting with CCash locally**
|
||||
|
||||
As CCash is just a means of keeping track of who has what, the economic system you use is entirely up to whomever hosts the instance.
|
||||
|
||||
It's suggested an admin should manage the instance to lower incentive to manipulate.
|
||||
I suggest an admin should manage the instance to lower incentive to manipulate balances.
|
||||
|
|
|
|||
12
docs/versioning.md
Normal file
12
docs/versioning.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Versioning
|
||||
|
||||
## Endpoint Version
|
||||
When changing an existing endpoint in a breaking way the version will increment in the path e.g `api/v1/user/log` -> `api/v2/user/log`. If the change is non-breaking then extra parameters will simply be added to the endpoint. If the older version is marked deprecated it will be documented in [endpoints.md](connected_services/how_to/endpoints.md)
|
||||
|
||||
## Release Version
|
||||
|
||||
Major changes (e.g `v1.0.0` -> `v2.0.0`) denote a breaking change as all previously deprecated endpoints will now be made defunct and wont be built with that release.
|
||||
|
||||
Minor changes (e.g `v1.0.0` -> `v1.1.0`) denote a non-breaking change that adds or changes something about CCash.
|
||||
|
||||
Patches (e.g `v1.0.0` -> `v1.0.1`) denote bug fixes or docs changes.
|
||||
|
|
@ -2,8 +2,8 @@ package bank_dom
|
|||
|
||||
struct Transaction
|
||||
{
|
||||
string from = "";
|
||||
string to = "";
|
||||
string counterparty = "";
|
||||
bool receiving = false;
|
||||
uint32 amount = 0;
|
||||
timestamp time;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom.h"
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
Transaction::Transaction()
|
||||
: from("")
|
||||
, to("")
|
||||
: counterparty("")
|
||||
, receiving(false)
|
||||
, amount((uint32_t)0ull)
|
||||
, time((uint64_t)0ull)
|
||||
{}
|
||||
|
||||
Transaction::Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time)
|
||||
: from(arg_from)
|
||||
, to(arg_to)
|
||||
Transaction::Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time)
|
||||
: counterparty(arg_counterparty)
|
||||
, receiving(arg_receiving)
|
||||
, amount(arg_amount)
|
||||
, time(arg_time)
|
||||
{}
|
||||
|
|
@ -36,8 +38,8 @@ bool Transaction::operator<(const Transaction& other) const noexcept
|
|||
void Transaction::swap(Transaction& other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(from, other.from);
|
||||
swap(to, other.to);
|
||||
swap(counterparty, other.counterparty);
|
||||
swap(receiving, other.receiving);
|
||||
swap(amount, other.amount);
|
||||
swap(time, other.time);
|
||||
}
|
||||
|
|
@ -45,8 +47,8 @@ void Transaction::swap(Transaction& other) noexcept
|
|||
std::ostream& operator<<(std::ostream& stream, const Transaction& value)
|
||||
{
|
||||
stream << "Transaction(";
|
||||
stream << "from="; stream << "\"" << value.from << "\"";
|
||||
stream << ",to="; stream << "\"" << value.to << "\"";
|
||||
stream << "counterparty="; stream << "\"" << value.counterparty << "\"";
|
||||
stream << ",receiving="; stream << (value.receiving ? "true" : "false");
|
||||
stream << ",amount="; stream << value.amount;
|
||||
stream << ",time="; stream << value.time;
|
||||
stream << ")";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -27,15 +29,15 @@ namespace bank_dom {
|
|||
|
||||
struct Transaction
|
||||
{
|
||||
std::string from;
|
||||
std::string to;
|
||||
std::string counterparty;
|
||||
bool receiving;
|
||||
uint32_t amount;
|
||||
uint64_t time;
|
||||
|
||||
size_t fbe_type() const noexcept { return 1; }
|
||||
|
||||
Transaction();
|
||||
Transaction(const std::string& arg_from, const std::string& arg_to, uint32_t arg_amount, uint64_t arg_time);
|
||||
Transaction(const std::string& arg_counterparty, bool arg_receiving, uint32_t arg_amount, uint64_t arg_time);
|
||||
Transaction(const Transaction& other) = default;
|
||||
Transaction(Transaction&& other) = default;
|
||||
~Transaction() = default;
|
||||
|
|
@ -60,10 +62,12 @@ struct Transaction
|
|||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Transaction> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Transaction>
|
||||
struct std::hash<bank_dom::Transaction>
|
||||
{
|
||||
typedef bank_dom::Transaction argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -75,8 +79,6 @@ struct hash<bank_dom::Transaction>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Logs
|
||||
|
|
@ -111,10 +113,12 @@ struct Logs
|
|||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Logs> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Logs>
|
||||
struct std::hash<bank_dom::Logs>
|
||||
{
|
||||
typedef bank_dom::Logs argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -126,8 +130,6 @@ struct hash<bank_dom::Logs>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct User
|
||||
|
|
@ -164,10 +166,12 @@ struct User
|
|||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::User> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::User>
|
||||
struct std::hash<bank_dom::User>
|
||||
{
|
||||
typedef bank_dom::User argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -179,8 +183,6 @@ struct hash<bank_dom::User>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
struct Global
|
||||
|
|
@ -216,10 +218,12 @@ struct Global
|
|||
|
||||
} // namespace bank_dom
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <> struct fmt::formatter<bank_dom::Global> : ostream_formatter {};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct hash<bank_dom::Global>
|
||||
struct std::hash<bank_dom::Global>
|
||||
{
|
||||
typedef bank_dom::Global argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -231,8 +235,6 @@ struct hash<bank_dom::Global>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace bank_dom {
|
||||
|
||||
} // namespace bank_dom
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom_final_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, from(buffer, 0)
|
||||
, to(buffer, 0)
|
||||
, counterparty(buffer, 0)
|
||||
, receiving(buffer, 0)
|
||||
, amount(buffer, 0)
|
||||
, time(buffer, 0)
|
||||
{}
|
||||
|
|
@ -17,8 +19,8 @@ FinalModel<::bank_dom::Transaction>::FinalModel(FBEBuffer& buffer, size_t offset
|
|||
size_t FinalModel<::bank_dom::Transaction>::fbe_allocation_size(const ::bank_dom::Transaction& fbe_value) const noexcept
|
||||
{
|
||||
size_t fbe_result = 0
|
||||
+ from.fbe_allocation_size(fbe_value.from)
|
||||
+ to.fbe_allocation_size(fbe_value.to)
|
||||
+ counterparty.fbe_allocation_size(fbe_value.counterparty)
|
||||
+ receiving.fbe_allocation_size(fbe_value.receiving)
|
||||
+ amount.fbe_allocation_size(fbe_value.amount)
|
||||
+ time.fbe_allocation_size(fbe_value.time)
|
||||
;
|
||||
|
|
@ -38,14 +40,14 @@ size_t FinalModel<::bank_dom::Transaction>::verify_fields() const noexcept
|
|||
size_t fbe_current_offset = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.verify();
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.verify();
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.verify();
|
||||
if (fbe_field_size == std::numeric_limits<std::size_t>::max())
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
fbe_current_offset += fbe_field_size;
|
||||
|
|
@ -79,13 +81,13 @@ size_t FinalModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction&
|
|||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.get(fbe_value.from);
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.get(fbe_value.counterparty);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.get(fbe_value.to);
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.get(fbe_value.receiving);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
|
|
@ -116,13 +118,13 @@ size_t FinalModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transac
|
|||
size_t fbe_current_size = 0;
|
||||
size_t fbe_field_size;
|
||||
|
||||
from.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = from.set(fbe_value.from);
|
||||
counterparty.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = counterparty.set(fbe_value.counterparty);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
to.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = to.set(fbe_value.to);
|
||||
receiving.fbe_offset(fbe_current_offset);
|
||||
fbe_field_size = receiving.set(fbe_value.receiving);
|
||||
fbe_current_offset += fbe_field_size;
|
||||
fbe_current_size += fbe_field_size;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -60,8 +62,8 @@ private:
|
|||
mutable size_t _offset;
|
||||
|
||||
public:
|
||||
FinalModel<std::string> from;
|
||||
FinalModel<std::string> to;
|
||||
FinalModel<std::string> counterparty;
|
||||
FinalModel<bool> receiving;
|
||||
FinalModel<uint32_t> amount;
|
||||
FinalModel<uint64_t> time;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "bank_dom_models.h"
|
||||
|
||||
namespace FBE {
|
||||
|
||||
FieldModel<::bank_dom::Transaction>::FieldModel(FBEBuffer& buffer, size_t offset) noexcept : _buffer(buffer), _offset(offset)
|
||||
, from(buffer, 4 + 4)
|
||||
, to(buffer, from.fbe_offset() + from.fbe_size())
|
||||
, amount(buffer, to.fbe_offset() + to.fbe_size())
|
||||
, counterparty(buffer, 4 + 4)
|
||||
, receiving(buffer, counterparty.fbe_offset() + counterparty.fbe_size())
|
||||
, amount(buffer, receiving.fbe_offset() + receiving.fbe_size())
|
||||
, time(buffer, amount.fbe_offset() + amount.fbe_size())
|
||||
{}
|
||||
|
||||
size_t FieldModel<::bank_dom::Transaction>::fbe_body() const noexcept
|
||||
{
|
||||
size_t fbe_result = 4 + 4
|
||||
+ from.fbe_size()
|
||||
+ to.fbe_size()
|
||||
+ counterparty.fbe_size()
|
||||
+ receiving.fbe_size()
|
||||
+ amount.fbe_size()
|
||||
+ time.fbe_size()
|
||||
;
|
||||
|
|
@ -37,8 +39,8 @@ size_t FieldModel<::bank_dom::Transaction>::fbe_extra() const noexcept
|
|||
_buffer.shift(fbe_struct_offset);
|
||||
|
||||
size_t fbe_result = fbe_body()
|
||||
+ from.fbe_extra()
|
||||
+ to.fbe_extra()
|
||||
+ counterparty.fbe_extra()
|
||||
+ receiving.fbe_extra()
|
||||
+ amount.fbe_extra()
|
||||
+ time.fbe_extra()
|
||||
;
|
||||
|
|
@ -75,17 +77,17 @@ bool FieldModel<::bank_dom::Transaction>::verify_fields(size_t fbe_struct_size)
|
|||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + from.fbe_size()) > fbe_struct_size)
|
||||
if ((fbe_current_size + counterparty.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!from.verify())
|
||||
if (!counterparty.verify())
|
||||
return false;
|
||||
fbe_current_size += from.fbe_size();
|
||||
fbe_current_size += counterparty.fbe_size();
|
||||
|
||||
if ((fbe_current_size + to.fbe_size()) > fbe_struct_size)
|
||||
if ((fbe_current_size + receiving.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
if (!to.verify())
|
||||
if (!receiving.verify())
|
||||
return false;
|
||||
fbe_current_size += to.fbe_size();
|
||||
fbe_current_size += receiving.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) > fbe_struct_size)
|
||||
return true;
|
||||
|
|
@ -141,17 +143,17 @@ void FieldModel<::bank_dom::Transaction>::get_fields(::bank_dom::Transaction& fb
|
|||
{
|
||||
size_t fbe_current_size = 4 + 4;
|
||||
|
||||
if ((fbe_current_size + from.fbe_size()) <= fbe_struct_size)
|
||||
from.get(fbe_value.from, "");
|
||||
if ((fbe_current_size + counterparty.fbe_size()) <= fbe_struct_size)
|
||||
counterparty.get(fbe_value.counterparty, "");
|
||||
else
|
||||
fbe_value.from = "";
|
||||
fbe_current_size += from.fbe_size();
|
||||
fbe_value.counterparty = "";
|
||||
fbe_current_size += counterparty.fbe_size();
|
||||
|
||||
if ((fbe_current_size + to.fbe_size()) <= fbe_struct_size)
|
||||
to.get(fbe_value.to, "");
|
||||
if ((fbe_current_size + receiving.fbe_size()) <= fbe_struct_size)
|
||||
receiving.get(fbe_value.receiving, false);
|
||||
else
|
||||
fbe_value.to = "";
|
||||
fbe_current_size += to.fbe_size();
|
||||
fbe_value.receiving = false;
|
||||
fbe_current_size += receiving.fbe_size();
|
||||
|
||||
if ((fbe_current_size + amount.fbe_size()) <= fbe_struct_size)
|
||||
amount.get(fbe_value.amount, (uint32_t)0ull);
|
||||
|
|
@ -203,8 +205,8 @@ void FieldModel<::bank_dom::Transaction>::set(const ::bank_dom::Transaction& fbe
|
|||
|
||||
void FieldModel<::bank_dom::Transaction>::set_fields(const ::bank_dom::Transaction& fbe_value) noexcept
|
||||
{
|
||||
from.set(fbe_value.from);
|
||||
to.set(fbe_value.to);
|
||||
counterparty.set(fbe_value.counterparty);
|
||||
receiving.set(fbe_value.receiving);
|
||||
amount.set(fbe_value.amount);
|
||||
time.set(fbe_value.time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: user_model.fbe
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -72,8 +74,8 @@ private:
|
|||
size_t _offset;
|
||||
|
||||
public:
|
||||
FieldModel<std::string> from;
|
||||
FieldModel<std::string> to;
|
||||
FieldModel<std::string> counterparty;
|
||||
FieldModel<bool> receiving;
|
||||
FieldModel<uint32_t> amount;
|
||||
FieldModel<uint64_t> time;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,24 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#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 {
|
||||
|
||||
std::string buffer_t::base64encode() const
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
@ -41,7 +43,6 @@
|
|||
#include <uuid/uuid.h>
|
||||
#undef HOST_NOT_FOUND
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#undef DELETE
|
||||
#undef ERROR
|
||||
#undef HOST_NOT_FOUND
|
||||
|
|
@ -321,10 +322,20 @@ private:
|
|||
|
||||
} // namespace FBE
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <>
|
||||
struct fmt::formatter<FBE::decimal_t> : formatter<std::string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const FBE::decimal_t& value, FormatContext& ctx) const
|
||||
{
|
||||
return formatter<string_view>::format((double)value, ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct hash<FBE::decimal_t>
|
||||
struct std::hash<FBE::decimal_t>
|
||||
{
|
||||
typedef FBE::decimal_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -337,8 +348,6 @@ struct hash<FBE::decimal_t>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Register a new enum-based flags macro
|
||||
|
|
@ -530,10 +539,20 @@ private:
|
|||
|
||||
} // namespace FBE
|
||||
|
||||
namespace std {
|
||||
#if defined(FMT_VERSION) && (FMT_VERSION >= 90000)
|
||||
template <>
|
||||
struct fmt::formatter<FBE::uuid_t> : formatter<std::string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const FBE::uuid_t& value, FormatContext& ctx) const
|
||||
{
|
||||
return formatter<string_view>::format(value.string(), ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct hash<FBE::uuid_t>
|
||||
struct std::hash<FBE::uuid_t>
|
||||
{
|
||||
typedef FBE::uuid_t argument_type;
|
||||
typedef size_t result_type;
|
||||
|
|
@ -548,8 +567,6 @@ struct hash<FBE::uuid_t>
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace FBE {
|
||||
|
||||
// Fast Binary Encoding buffer based on the dynamic byte buffer
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "fbe_final_models.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace FBE {
|
||||
|
||||
|
|
@ -536,8 +538,8 @@ inline size_t FinalModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) c
|
|||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
|
|
@ -568,8 +570,8 @@ inline size_t FinalModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>&
|
|||
FinalModel<TValue> fbe_model_value(_buffer, fbe_offset() + 4);
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
size_t offset_key = fbe_model_key.get(key);
|
||||
fbe_model_key.fbe_shift(offset_key);
|
||||
fbe_model_value.fbe_shift(offset_key);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "fbe_models.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// Automatically generated by the Fast Binary Encoding compiler, do not modify!
|
||||
// https://github.com/chronoxor/FastBinaryEncoding
|
||||
// Source: FBE
|
||||
// Version: 1.7.0.0
|
||||
// FBE version: 1.14.1.0
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace FBE {
|
||||
|
||||
|
|
@ -618,8 +620,8 @@ inline void FieldModelMap<TKey, TValue>::get(std::map<TKey, TValue>& values) con
|
|||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
|
|
@ -640,8 +642,8 @@ inline void FieldModelMap<TKey, TValue>::get(std::unordered_map<TKey, TValue>& v
|
|||
auto fbe_model = (*this)[0];
|
||||
for (size_t i = fbe_map_size; i-- > 0;)
|
||||
{
|
||||
TKey key;
|
||||
TValue value;
|
||||
TKey key = TKey();
|
||||
TValue value = TValue();
|
||||
fbe_model.first.get(key);
|
||||
fbe_model.second.get(value);
|
||||
values.emplace(key, value);
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ private:
|
|||
static ChangeFlag<false> save_flag;
|
||||
#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 unique if the operation is gonna user iterators
|
||||
// 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
|
||||
static std::shared_mutex iter_lock;
|
||||
|
||||
public:
|
||||
|
|
@ -43,16 +43,22 @@ public:
|
|||
static size_t SumBal() noexcept;
|
||||
|
||||
static BankResponse GetBal(const std::string &name) noexcept;
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
static BankResponse GetLogs(const std::string &name) noexcept;
|
||||
#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 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 BankResponse SetBal(const std::string &name, uint32_t amount) noexcept;
|
||||
static BankResponse SetBal(const std::string &name, int64_t amount) noexcept;
|
||||
static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
|
||||
static bool Contains(const std::string &name) noexcept;
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -11,21 +11,25 @@ using namespace drogon;
|
|||
class api : public HttpController<api>
|
||||
{
|
||||
public:
|
||||
#if API_VERSION >= 1
|
||||
static void GetBal(req_args, const std::string &name);
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
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 ChangePassword(req_args);
|
||||
static void VerifyPassword(req_args);
|
||||
|
||||
static void ChangePassword(req_args);
|
||||
static void AdminGetLogs(req_args, const std::string& name);
|
||||
static void AdminChangePassword(req_args);
|
||||
static void AdminVerifyAccount(req_args);
|
||||
static void SetBal(req_args);
|
||||
static void ImpactBal(req_args);
|
||||
|
||||
static void Help(req_args);
|
||||
static void Close(req_args);
|
||||
static void Contains(req_args, const std::string &name);
|
||||
static void AdminVerifyAccount(req_args);
|
||||
static void PruneUsers(req_args);
|
||||
static void ApiProperties(req_args);
|
||||
|
||||
|
|
@ -33,41 +37,55 @@ public:
|
|||
static void AdminAddUser(req_args);
|
||||
static void DelSelf(req_args);
|
||||
static void AdminDelUser(req_args);
|
||||
#endif
|
||||
|
||||
METHOD_LIST_BEGIN
|
||||
|
||||
#if API_VERSION >= 1
|
||||
|
||||
//Usage
|
||||
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
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
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
|
||||
#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::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>");
|
||||
|
||||
//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::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::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::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
|
||||
|
||||
//System Usage
|
||||
METHOD_ADD(api::Help, "/v1/help", Get, Options);
|
||||
METHOD_ADD(api::Help, "/help", Get, Options);
|
||||
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
|
||||
METHOD_ADD(api::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::ApiProperties, "/properties", Get, Options);
|
||||
|
||||
//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::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)
|
||||
#endif
|
||||
|
||||
METHOD_LIST_END
|
||||
};
|
||||
|
|
@ -10,12 +10,22 @@ using namespace simdjson;
|
|||
struct Log
|
||||
{
|
||||
private:
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
ChangeFlag<true> log_flag;
|
||||
std::string log_snapshot = "null";
|
||||
#endif
|
||||
|
||||
ChangeFlag<true> log_flag_v2;
|
||||
std::string log_snapshot_v2 = "null";
|
||||
|
||||
public:
|
||||
std::deque<Transaction> data;
|
||||
|
||||
std::string GetLogs() noexcept;
|
||||
void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept;
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
std::string GetLogs(const std::string& name) noexcept;
|
||||
#endif
|
||||
std::string GetLogsV2() noexcept;
|
||||
std::string GetLogsRange(size_t n, size_t m) noexcept;
|
||||
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
#pragma once
|
||||
#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
|
||||
{
|
||||
std::string str;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
struct Transaction
|
||||
{
|
||||
std::string from = "", to = "";
|
||||
std::string counterparty = "";
|
||||
bool receiving = false;
|
||||
uint32_t amount = 0;
|
||||
time_t time = 0;
|
||||
|
||||
Transaction() noexcept;
|
||||
Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time) noexcept;
|
||||
Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
|
||||
};
|
||||
|
|
|
|||
55
main.cpp
55
main.cpp
|
|
@ -34,46 +34,48 @@ int main(int argc, char **argv)
|
|||
uint8_t temp[16]{16, 0, 0, 0, 4};
|
||||
users_save.write((char *)temp, 16);
|
||||
users_save.close();
|
||||
std::cout << "User save file generated\nUsage: sudo ./bank <admin account> <saving frequency in minutes>\n";
|
||||
std::cout << "User save file generated\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "File cannot be created\n";
|
||||
std::cerr << "File cannot be created (may already exist)\n";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (argc != 3)
|
||||
if (argc < 3)
|
||||
{
|
||||
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes>\n";
|
||||
return 0;
|
||||
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
|
||||
return -1;
|
||||
}
|
||||
if (geteuid() != 0)
|
||||
{
|
||||
std::cerr << "ERROR: CCash MUST be ran as root\n";
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
|
||||
std::cout
|
||||
<< "\nAPI Version : " << API_VERSION
|
||||
<< "\n\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
|
||||
<< "\nAPI : v2.6.1\n"
|
||||
<< "\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
|
||||
<< "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled")
|
||||
<< "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.1 : " << (__builtin_cpu_supports("sse4.1") ? "enabled" : "disabled")
|
||||
<< "\nSSE 4.2 : " << (__builtin_cpu_supports("sse4.2") ? "enabled" : "disabled")
|
||||
#if MULTI_THREADED
|
||||
<< "\n\nThreads : " << get_nprocs() + 1
|
||||
<< "\n\nThreads : " << get_nprocs() + saving_freq
|
||||
<< "\nMulti threading : enabled";
|
||||
#else
|
||||
<< "\n\nThreads : " << 2
|
||||
<< "\n\nThreads : " << 1 + saving_freq
|
||||
<< "\nMulti threading : disabled";
|
||||
#endif
|
||||
|
||||
//Loading users from users.json
|
||||
//Loading users from users.dat
|
||||
Bank::Load();
|
||||
size_t num_of_logs = Bank::NumOfLogs();
|
||||
size_t num_of_users = Bank::NumOfUsers();
|
||||
std::cout << "\n\nLoaded " << num_of_users << " Users ~" << (float)(sizeof(User) * num_of_users) / 1048576 << "Mb"
|
||||
<< "\nLoaded " << num_of_logs << " Logs ~" << (float)(num_of_logs * (91 + 80 + (max_name_size * 2))) / 1048576 << "Mb" //91:string representation(heap), sizeof(Transaction), max_name_size*2:filled to&from(heap)
|
||||
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 " << Bank::SumBal() << " C$H"
|
||||
<< std::endl; //flushing before EventLoop
|
||||
|
||||
|
|
@ -88,19 +90,24 @@ int main(int argc, char **argv)
|
|||
Bank::admin_account = argv[1];
|
||||
|
||||
//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
|
||||
{
|
||||
std::thread([saving_freq]()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
std::cout << "Saving " << std::time(0) << "...\n"
|
||||
<< Bank::Save();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
|
||||
std::cout << "Saving " << std::time(0) << "...\n" << Bank::Save();
|
||||
}
|
||||
})
|
||||
.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
|
||||
|
||||
|
|
|
|||
83
src/bank.cpp
83
src/bank.cpp
|
|
@ -36,7 +36,7 @@ inline bool ValidUsername(const std::string &name) noexcept
|
|||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -85,11 +85,14 @@ BankResponse Bank::GetBal(const std::string &name) noexcept
|
|||
return {k200OK, std::to_string(res)};
|
||||
}
|
||||
}
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
BankResponse Bank::GetLogs(const std::string &name) noexcept
|
||||
{
|
||||
BankResponse res;
|
||||
if (!Bank::users.modify_if(name, [&res](User &u) { res = {k200OK, u.log.GetLogs()}; }))
|
||||
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; }))
|
||||
{
|
||||
return {k404NotFound, "\"User not found\""};
|
||||
}
|
||||
|
|
@ -99,6 +102,44 @@ BankResponse Bank::GetLogs(const std::string &name) noexcept
|
|||
}
|
||||
}
|
||||
#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
|
||||
{
|
||||
if (!amount)
|
||||
|
|
@ -123,7 +164,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a)
|
||||
#endif
|
||||
{
|
||||
//if A can afford it
|
||||
//if "A" can afford it
|
||||
if (a.balance < amount)
|
||||
{
|
||||
res = {k400BadRequest, "\"Insufficient funds\""};
|
||||
|
|
@ -132,7 +173,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
{
|
||||
a.balance -= amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
a.log.AddTrans(a_name, b_name, amount, current_time);
|
||||
a.log.AddTrans(b_name, false, amount, current_time);
|
||||
#endif
|
||||
res = {k200OK, std::to_string(a.balance)};
|
||||
}
|
||||
|
|
@ -145,7 +186,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
#if MAX_LOG_SIZE > 0
|
||||
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
|
||||
b.balance += amount;
|
||||
b.log.AddTrans(a_name, b_name, amount, current_time);
|
||||
b.log.AddTrans(a_name, true, amount, current_time);
|
||||
});
|
||||
#else
|
||||
Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; });
|
||||
|
|
@ -160,15 +201,20 @@ bool Bank::VerifyPassword(const std::string &name, const std::string_view &attem
|
|||
Bank::users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); });
|
||||
return res;
|
||||
}
|
||||
|
||||
void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); });
|
||||
}
|
||||
BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept
|
||||
BankResponse Bank::SetBal(const std::string &name, int64_t amount) noexcept
|
||||
{
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [amount](User &u) { u.balance = amount; }))
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) {
|
||||
amount -= u.balance;
|
||||
u.balance += amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
|
||||
#endif
|
||||
}))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k204NoContent, std::nullopt}; //returns new balance
|
||||
|
|
@ -185,7 +231,13 @@ BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept
|
|||
return {k400BadRequest, "\"Amount cannot be 0\""};
|
||||
}
|
||||
uint32_t bal;
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, amount](User &u) { bal = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); }))
|
||||
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, &amount](User &u) {
|
||||
if (u.balance < (amount * -1)) { amount = -int64_t(u.balance); };
|
||||
bal = u.balance += amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
|
||||
#endif
|
||||
}))
|
||||
{
|
||||
SET_CHANGES_ON;
|
||||
return {k200OK, std::to_string(bal)}; //may return new balance
|
||||
|
|
@ -212,15 +264,26 @@ BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept
|
|||
#endif
|
||||
for (const auto &u : users)
|
||||
{
|
||||
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
#if RETURN_ON_DEL
|
||||
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) {
|
||||
bal += u.balance;
|
||||
#else
|
||||
if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) {
|
||||
#endif
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
||||
return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal);
|
||||
#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);
|
||||
#endif
|
||||
}))
|
||||
|
|
|
|||
183
src/bank_api.cpp
183
src/bank_api.cpp
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
|
||||
|
||||
static thread_local ondemand::parser parser;
|
||||
thread_local ondemand::parser parser;
|
||||
#define SIMD_JSON_GEN \
|
||||
simdjson::padded_string input(req->getBody()); \
|
||||
auto doc = parser.iterate(input);
|
||||
ondemand::document doc;
|
||||
|
||||
#define RESPONSE_PARSE(R) \
|
||||
auto resp = HttpResponse::newCustomHttpResponse(R); \
|
||||
|
|
@ -22,13 +22,13 @@ static thread_local ondemand::parser parser;
|
|||
|
||||
#define NAME_PARAM req->getParameter("name")
|
||||
|
||||
#if API_VERSION >= 1
|
||||
|
||||
//Usage
|
||||
void api::GetBal(req_args, const std::string &name)
|
||||
{
|
||||
RESPONSE_PARSE(Bank::GetBal(name));
|
||||
}
|
||||
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
void api::GetLogs(req_args)
|
||||
{
|
||||
#if MAX_LOG_SIZE > 0
|
||||
|
|
@ -40,26 +40,64 @@ void api::GetLogs(req_args)
|
|||
callback(resp);
|
||||
#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)
|
||||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto amount = doc["amount"].get_uint64();
|
||||
if (name.error() || amount.error())
|
||||
std::string_view name;
|
||||
uint64_t amount; // as simdjson lacks .get(uint32_t support)
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = Bank::SendFunds(NAME_PARAM, name_val.str, amount.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::SendFunds(NAME_PARAM, name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
|
|
@ -71,20 +109,20 @@ void api::ChangePassword(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pass = doc["pass"].get_string();
|
||||
if (pass.error())
|
||||
std::string_view pass;
|
||||
if (doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
Bank::ChangePassword(NAME_PARAM, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
|
|
@ -95,24 +133,23 @@ void api::AdminChangePassword(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto pass = doc["pass"].get_string();
|
||||
if (name.error() || pass.error())
|
||||
std::string_view name, pass;
|
||||
if (doc["name"].get(name) || doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
if (Bank::Contains(name_val.str))
|
||||
{
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
Bank::ChangePassword(name_val.str, pass_val.str);
|
||||
res = BankResponse{k204NoContent, std::nullopt};
|
||||
}
|
||||
|
|
@ -128,22 +165,22 @@ void api::SetBal(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto amount = doc["amount"].get_uint64();
|
||||
if (name.error() || amount.error())
|
||||
std::string_view name;
|
||||
uint64_t amount;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = Bank::SetBal(name_val.str, amount.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::SetBal(name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
|
|
@ -152,22 +189,22 @@ void api::ImpactBal(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto amount = doc["amount"].get_int64();
|
||||
if (name.error() || amount.error())
|
||||
std::string_view name;
|
||||
int64_t amount;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
res = Bank::ImpactBal(name_val.str, amount.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::ImpactBal(name_val.str, amount);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
|
|
@ -205,15 +242,7 @@ void api::AdminVerifyAccount(req_args)
|
|||
}
|
||||
void api::ApiProperties(req_args)
|
||||
{
|
||||
std::string info = "{\"version\":" + std::to_string(API_VERSION) + ",\"max_log\":" + std::to_string(MAX_LOG_SIZE) + ",\"add_user_open\":" + std::to_string(ADD_USER_OPEN);
|
||||
if constexpr (RETURN_ON_DEL)
|
||||
{
|
||||
info += ",\"return_on_del\":\"" + std::string(return_account) + "\"}";
|
||||
}
|
||||
else
|
||||
{
|
||||
info += "}";
|
||||
}
|
||||
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") + '}';
|
||||
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k200OK, std::move(info)});
|
||||
CORS;
|
||||
CACHE_FOREVER;
|
||||
|
|
@ -223,32 +252,31 @@ void api::PruneUsers(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
auto time = doc["time"].get_int64();
|
||||
auto amount = doc["amount"].get_uint64();
|
||||
if (time.error() || amount.error())
|
||||
int64_t time;
|
||||
if (doc["time"].get(time) || doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Bank::PruneUsers(time.value(), amount.value());
|
||||
res = Bank::PruneUsers(time, amount);
|
||||
}
|
||||
#else
|
||||
auto amount = doc["amount"].get_uint64();
|
||||
if (amount.error())
|
||||
if (doc["amount"].get(amount) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Bank::PruneUsers(amount.value());
|
||||
res = Bank::PruneUsers(amount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -259,25 +287,23 @@ void api::AddUser(req_args)
|
|||
{
|
||||
if constexpr (ADD_USER_OPEN)
|
||||
{
|
||||
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto pass = doc["pass"].get_string();
|
||||
if (name.error() || pass.error())
|
||||
std::string_view name, pass;
|
||||
if (doc["name"].get(name) || doc["pass"].get(pass))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
res = Bank::AddUser(name_val.str, 0, pass_val.str);
|
||||
}
|
||||
}
|
||||
|
|
@ -295,24 +321,24 @@ void api::AdminAddUser(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
auto amount = doc["amount"].get_uint64();
|
||||
auto pass = doc["pass"].get_string();
|
||||
if (name.error() || amount.error() || pass.error())
|
||||
std::string_view name;
|
||||
uint64_t amount;
|
||||
std::string_view pass;
|
||||
if (doc["name"].get(name) || doc["amount"].get(amount) || doc["pass"].get(pass) || (amount > std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper pass_val(pass.value());
|
||||
res = Bank::AddUser(name_val.str, amount.value(), pass_val.str);
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
StrFromSV_Wrapper pass_val(pass);
|
||||
res = Bank::AddUser(name_val.str, amount, pass_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
|
|
@ -326,23 +352,22 @@ void api::AdminDelUser(req_args)
|
|||
{
|
||||
SIMD_JSON_GEN;
|
||||
BankResponse res;
|
||||
if (doc.error())
|
||||
if (parser.iterate(input).get(doc))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Invalid JSON\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = doc["name"].get_string();
|
||||
if (name.error())
|
||||
std::string_view name;
|
||||
if (doc["name"].get(name))
|
||||
{
|
||||
res = BankResponse{k400BadRequest, "\"Missing JSON arg(s)\""};
|
||||
res = BankResponse{k400BadRequest, "\"Missing/Invalid JSON arg(s)\""};
|
||||
}
|
||||
else
|
||||
{
|
||||
StrFromSV_Wrapper name_val(name.value());
|
||||
StrFromSV_Wrapper name_val(name);
|
||||
res = Bank::DelUser(name_val.str);
|
||||
}
|
||||
}
|
||||
RESPONSE_PARSE(std::move(res));
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
157
src/log.cpp
157
src/log.cpp
|
|
@ -1,22 +1,27 @@
|
|||
#include "log.h"
|
||||
|
||||
void Log::AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept
|
||||
void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept
|
||||
{
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
log_flag.SetChangesOn();
|
||||
#endif
|
||||
log_flag_v2.SetChangesOn();
|
||||
|
||||
if (data.size() == MAX_LOG_SIZE)
|
||||
{
|
||||
data.pop_back();
|
||||
data.pop_front();
|
||||
}
|
||||
data.emplace_back(from, to, amount, time);
|
||||
data.emplace_back(counterparty_str, receiving, amount, time);
|
||||
}
|
||||
|
||||
std::string Log::GetLogs() noexcept
|
||||
#if USE_DEPRECATED_ENDPOINTS
|
||||
std::string Log::GetLogs(const std::string& name) noexcept
|
||||
{
|
||||
if (log_flag.GetChangeState() && data.size()) //if there are changes
|
||||
if (log_flag.GetChangeState() && data.size()) // if there are changes
|
||||
{
|
||||
log_snapshot.resize(0);
|
||||
//re-generate snapshot
|
||||
size_t predicted_size = ((59 + (2 * max_name_size)) * data.size()) + 1;
|
||||
size_t predicted_size = ((57 + (2 * max_name_size)) * data.size()) + 1;
|
||||
if (log_snapshot.capacity() < predicted_size)
|
||||
{
|
||||
log_snapshot.reserve(predicted_size);
|
||||
|
|
@ -24,18 +29,140 @@ std::string Log::GetLogs() noexcept
|
|||
log_snapshot = '['; //1
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
log_snapshot += "{\"to\":\""; //8
|
||||
log_snapshot += data[i].to; //max_name_size?
|
||||
log_snapshot += "\",\"from\":\""; //10
|
||||
log_snapshot += data[i].from; //max_name_size?
|
||||
log_snapshot += "\",\"amount\":"; //12
|
||||
log_snapshot += std::to_string(data[i].amount); //10?
|
||||
log_snapshot += ",\"time\":"; //8
|
||||
log_snapshot += std::to_string(data[i].time); //10?
|
||||
log_snapshot += "},"; //2
|
||||
log_snapshot += "{\"to\":\""; //7
|
||||
log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
|
||||
log_snapshot += "\",\"from\":\""; //10
|
||||
log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
|
||||
log_snapshot += "\",\"amount\":"; //11
|
||||
log_snapshot += std::to_string(data[i].amount); //10?
|
||||
log_snapshot += ",\"time\":"; //8
|
||||
log_snapshot += std::to_string(data[i].time); //10?
|
||||
log_snapshot += "},"; //2
|
||||
}
|
||||
log_snapshot.back() = ']';
|
||||
log_flag.SetChangesOff();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "transaction.h"
|
||||
|
||||
Transaction::Transaction() noexcept {};
|
||||
Transaction::Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time_val) noexcept : from(from_str), to(to_str), amount(amount), time(time_val) {}
|
||||
Transaction::Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
const bank_dom::Transaction &temp = u.logs.value().data[i];
|
||||
log.data.emplace_front(temp.from, temp.to, temp.amount, temp.time);
|
||||
log.data.emplace_front(temp.counterparty, temp.receiving, temp.amount, temp.time);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -43,7 +43,7 @@ bank_dom::User User::Encode() const noexcept
|
|||
save_log.data.reserve(this->log.data.size());
|
||||
for (const Transaction &t : this->log.data)
|
||||
{
|
||||
save_log.data.emplace_back(t.from, t.to, t.amount, t.time);
|
||||
save_log.data.emplace_back(t.counterparty, t.receiving, t.amount, t.time);
|
||||
}
|
||||
return bank_dom::User(balance, password, save_log);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ inline bool ValidUsername(const std::string &name) noexcept
|
|||
}
|
||||
for (char c : name)
|
||||
{
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue