Skip to content

Commit b235708

Browse files
committed
Creating arq example in c++
1 parent 260fbef commit b235708

File tree

8 files changed

+295
-1
lines changed

8 files changed

+295
-1
lines changed

LibStored.slnx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<Project Path="examples/LibStored.Net.Example.ServiceDefaults/LibStored.Net.Example.ServiceDefaults.csproj" />
77
<Project Path="examples/LibStored.Net.Example/LibStored.Net.Example.csproj" />
88
</Folder>
9+
<Folder Name="/examples/arq/" />
910
<Folder Name="/Solution Items/">
1011
<File Path=".editorconfig" />
1112
<File Path="Directory.Build.props" />
@@ -20,4 +21,4 @@
2021
<Project Path="test/LibStored.Net.IntegrationTests/LibStored.Net.IntegrationTests.csproj" />
2122
<Project Path="test/LibStored.Net.Tests/LibStored.Net.Tests.csproj" />
2223
</Folder>
23-
</Solution>
24+
</Solution>

examples/Arq/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/
2+
extern/
3+
libstored/

examples/Arq/ArqStore.st

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-FileCopyrightText: 2020-2023 Jochem Rutgers
2+
//
3+
// SPDX-License-Identifier: CC0-1.0
4+
5+
// This is a comment. The comment is always till the end of the line.
6+
7+
// Basically, a variable is defined as:
8+
// <type> <name>
9+
//
10+
// Only built-in types can be used (although a blob can be cast to anything),
11+
// and the name consists of all ASCII-printable characters (ASCII 0x20-0x7e).
12+
// All variable are (default) initialized to zero or equivalent.
13+
// More on that later on, but this creates two variables:
14+
15+
int32 hello
16+
double world
17+
18+
// This file is named Hello.st, so a C++ object stored::Hello is generated,
19+
// which can be included using Hello.h.
20+
21+
// Check out scripts/st.vim for syntax highlighting in Vim.
22+
23+
int32 a short int that fits in the response buffers
24+
string:32 a long string that does not fit in the response buffers
25+
26+
uint32=32 MTU
27+
double=1e-5 ber
28+
uint32 injected errors

examples/Arq/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(ArqExample)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
7+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
8+
find_package(Libstored COMPONENTS ZeroMQ REQUIRED)
9+
10+
add_executable(arq main.cpp)
11+
libstored_generate(TARGET arq STORES ArqStore.st)

examples/Arq/Dockerfile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Add ARG for libstored version
2+
ARG LIBSTORED_VERSION=1.8.0
3+
4+
FROM ubuntu:22.04 as builder
5+
6+
# Use the ARG after FROM
7+
ARG LIBSTORED_VERSION
8+
9+
RUN apt-get update && \
10+
apt-get install -y --no-install-recommends \
11+
build-essential \
12+
git-core \
13+
cmake \
14+
pkg-config \
15+
python3 \
16+
python3-pip \
17+
python3-setuptools \
18+
doxygen \
19+
plantuml \
20+
python3-venv \
21+
python3-dev \
22+
lsb-release \
23+
libgl1 \
24+
libegl1 \
25+
libxkbcommon0 \
26+
ninja-build \
27+
libzmq3-dev \
28+
libcairo2 \
29+
sudo \
30+
wget && \
31+
apt-get clean && \
32+
rm -rf /var/lib/apt/lists/*
33+
34+
WORKDIR /tmp/src/extern
35+
36+
RUN wget https://github.com/DEMCON/libstored/archive/refs/tags/v${LIBSTORED_VERSION}.tar.gz && \
37+
tar -xzf v${LIBSTORED_VERSION}.tar.gz --transform="s/libstored-${LIBSTORED_VERSION}/libstored/" && \
38+
rm v${LIBSTORED_VERSION}.tar.gz
39+
40+
COPY . /tmp/src/
41+
42+
RUN python3 -m pip install libstored
43+
RUN cd /tmp/src/ && chmod +x build.sh && ./build.sh
44+
45+
# Create production image
46+
FROM ubuntu:22.04
47+
48+
RUN apt-get update && \
49+
apt-get install -y --no-install-recommends \
50+
libzmq5 && \
51+
apt-get clean && \
52+
rm -rf /var/lib/apt/lists/*
53+
54+
# Copy the examples
55+
COPY --from=builder /tmp/src/build/arq /app/
56+
57+
WORKDIR /app
58+
59+
CMD ["./arq"]

examples/Arq/build.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
mkdir -p build
2+
cd build
3+
cmake ..
4+
cmake --build . --config Debug
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SPDX-FileCopyrightText: 2020-2023 Jochem Rutgers
2+
#
3+
# SPDX-License-Identifier: MPL-2.0
4+
5+
cmake_policy(VERSION 3.10)
6+
include(FindPackageHandleStandardArgs)
7+
8+
set(PYTHON_EXECUTABLE "/usr/bin/python3")
9+
10+
file(TO_CMAKE_PATH "/usr/local/lib/python3.10/dist-packages/libstored/data" LIBSTORED_SOURCE_DIR)
11+
12+
if(EXISTS ${LIBSTORED_SOURCE_DIR}/cmake/libstored.cmake)
13+
message(STATUS "Using libstored from ${LIBSTORED_SOURCE_DIR}")
14+
15+
list(APPEND CMAKE_MODULE_PATH ${LIBSTORED_SOURCE_DIR}/dist/common)
16+
17+
foreach(c IN LISTS Libstored_FIND_COMPONENTS)
18+
set(_req)
19+
20+
if(${Libstored_FIND_REQUIRED_${c}})
21+
set(_req "REQUIRED")
22+
endif()
23+
24+
if("${c}" STREQUAL "ZeroMQ")
25+
find_package(ZeroMQ ${_req})
26+
set(LIBSTORED_HAVE_LIBZMQ ON CACHE INTERNAL "Enable ZeroMQ" FORCE)
27+
elseif("${c}" STREQUAL "Zth")
28+
find_package(Zth ${_req})
29+
set(LIBSTORED_HAVE_ZTH ON CACHE INTERNAL "Enable Zth" FORCE)
30+
elseif("${c}" STREQUAL "Heatshrink")
31+
find_package(Heatshrink ${_req})
32+
set(LIBSTORED_HAVE_HEATSHRINK ON CACHE INTERNAL "Enable heatshrink" FORCE)
33+
elseif("${c}" STREQUAL "Qt5")
34+
find_package(Qt5 ${_req} COMPONENTS Core)
35+
set(LIBSTORED_HAVE_QT ON CACHE INTERNAL "Enable Qt5" FORCE)
36+
elseif("${c}" STREQUAL "Qt6")
37+
find_package(Qt6 ${_req} COMPONENTS Core)
38+
set(LIBSTORED_HAVE_QT ON CACHE INTERNAL "Enable Qt6" FORCE)
39+
endif()
40+
endforeach()
41+
42+
include(${LIBSTORED_SOURCE_DIR}/cmake/libstored.cmake REQUIRED)
43+
find_package_handle_standard_args(
44+
Libstored
45+
REQUIRED_VARS LIBSTORED_SOURCE_DIR
46+
VERSION_VAR LIBSTORED_VERSION_BASE
47+
)
48+
endif()

examples/Arq/main.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include "ArqStore.h"
2+
3+
#include <stdlib.h>
4+
#include <stored>
5+
#include <string.h>
6+
7+
static stored::Synchronizer synchronizer;
8+
9+
class ArqStore
10+
: public STORE_T(ArqStore, stored::Synchronizable, stored::ArqStoreBase) {
11+
STORE_CLASS(ArqStore, stored::Synchronizable, stored::ArqStoreBase)
12+
public:
13+
ArqStore() is_default
14+
};
15+
16+
static ArqStore store;
17+
18+
/*!
19+
* \brief Simulate a lossy channel.
20+
*
21+
* Depending on the bit error rate (ber) set in the store, bits are flipped.
22+
* Moreover, it allows to set an MTU via the store.
23+
*/
24+
class LossyChannel : public stored::ProtocolLayer {
25+
STORED_CLASS_NOCOPY(LossyChannel)
26+
public:
27+
typedef stored::ProtocolLayer base;
28+
29+
LossyChannel(ProtocolLayer* up = nullptr, ProtocolLayer* down = nullptr)
30+
: base(up, down)
31+
{}
32+
33+
virtual ~LossyChannel() override is_default
34+
35+
virtual void decode(void* buffer, size_t len) override
36+
{
37+
char* buffer_ = static_cast<char*>(buffer);
38+
for(size_t i = 0; i < len; i++)
39+
buffer_[i] = lossyByte(buffer_[i]);
40+
41+
//printBuffer(buffer, len, "> ");
42+
base::decode(buffer, len);
43+
}
44+
45+
virtual void encode(void const* buffer, size_t len, bool last = true) override
46+
{
47+
// cppcheck-suppress allocaCalled
48+
char* buffer_ = (char*)alloca(len);
49+
for(size_t i = 0; i < len; i++)
50+
buffer_[i] = lossyByte(static_cast<char const*>(buffer)[i]);
51+
52+
//printBuffer(buffer_, len, "< ");
53+
base::encode(buffer_, len, last);
54+
}
55+
56+
using base::encode;
57+
58+
// Bit error rate
59+
double ber() const
60+
{
61+
return store.ber;
62+
}
63+
64+
char lossyByte(char b)
65+
{
66+
for(int i = 0; i < 8; i++) {
67+
double p =
68+
#ifdef STORED_OS_WINDOWS
69+
(double)::rand() / RAND_MAX;
70+
#else
71+
// flawfinder: ignore
72+
drand48();
73+
#endif
74+
if(p < ber()) {
75+
// Inject an error.
76+
b = (char)(b ^ (char)(1 << (rand() % 8)));
77+
store.injected_errors = store.injected_errors + 1;
78+
}
79+
}
80+
return b;
81+
}
82+
83+
virtual size_t mtu() const override
84+
{
85+
return store.MTU.as<size_t>();
86+
}
87+
};
88+
89+
int main()
90+
{
91+
printf("\nStart synchorizer from ZmqLayer on port 5555.\n");
92+
synchronizer.map(store);
93+
94+
stored::SegmentationLayer segmentation;
95+
stored::SyncConnection const& connection = synchronizer.connect(segmentation);
96+
97+
stored::ArqLayer arq;
98+
arq.wrap(segmentation);
99+
100+
stored::Crc16Layer crc;
101+
crc.wrap(arq);
102+
103+
stored::AsciiEscapeLayer escape;
104+
escape.wrap(crc);
105+
106+
stored::TerminalLayer terminal;
107+
terminal.wrap(escape);
108+
109+
stored::BufferLayer buffer;
110+
buffer.wrap(terminal);
111+
112+
LossyChannel lossy;
113+
lossy.wrap(buffer);
114+
115+
stored::SyncZmqLayer zmq(nullptr, "tcp://*:5555", true);
116+
zmq.wrap(lossy);
117+
118+
stored::Poller poller;
119+
stored::PollableZmqLayer pollableZmq(zmq, stored::Pollable::PollIn);
120+
121+
while(true) {
122+
// 1 s timeout, to force keep alive once in a while.
123+
stored::Poller::Result const& result = poller.poll(1000);
124+
125+
if(result.empty()) {
126+
switch(errno) {
127+
case EAGAIN:
128+
case EINTR:
129+
break;
130+
default:
131+
perror("poll failed");
132+
return 1;
133+
}
134+
}
135+
136+
zmq.recv();
137+
synchronizer.process();
138+
}
139+
return 0;
140+
}

0 commit comments

Comments
 (0)