Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
observer_pattern.cpp
Go to the documentation of this file.
1/*****************************************************************************
2BSD 3-Clause License
3
4Copyright (c) 2024, Network System Project
5All rights reserved.
6*****************************************************************************/
7
33
34#include <chrono>
35#include <iostream>
36#include <map>
37#include <mutex>
38#include <span>
39#include <string>
40#include <thread>
41#include <vector>
42
43using namespace kcenon::network;
44
52public:
53 explicit chat_observer(const std::string& name) : name_(name) {}
54
55 auto on_connected() -> void override {
56 std::cout << "[" << name_ << "] Connected to server." << std::endl;
57 }
58
59 auto on_disconnected(std::optional<std::string_view> reason) -> void override {
60 std::cout << "[" << name_ << "] Disconnected";
61 if (reason.has_value()) {
62 std::cout << " (reason: " << reason.value() << ")";
63 }
64 std::cout << std::endl;
65 }
66
67 auto on_receive(std::span<const uint8_t> data) -> void override {
68 std::string message(data.begin(), data.end());
69 std::cout << "[" << name_ << "] Received: " << message << std::endl;
71 }
72
73 auto on_error(std::error_code ec) -> void override {
74 std::cerr << "[" << name_ << "] Error: " << ec.message() << std::endl;
75 }
76
77 [[nodiscard]] auto message_count() const -> int { return message_count_; }
78
79private:
80 std::string name_;
82};
83
90public:
91 auto on_receive(std::span<const uint8_t> data) -> void override {
92 std::string message(data.begin(), data.end());
93 std::cout << "[ReceiveOnly] Got: " << message << std::endl;
94 }
95};
96
97int main() {
98 std::cout << "=== Observer Pattern Example ===" << std::endl;
99
100 // --- Start a local echo server ---
102 constexpr uint16_t port = 9004;
103
104 auto server = tcp.create_server({
105 .port = port,
106 .server_id = "ObserverTestServer",
107 });
108
109 std::mutex sessions_mutex;
110 std::map<std::string, std::shared_ptr<interfaces::i_session>> sessions;
111
112 server->set_connection_callback(
113 [&sessions, &sessions_mutex](std::shared_ptr<interfaces::i_session> session) {
114 std::lock_guard<std::mutex> lock(sessions_mutex);
115 sessions[std::string(session->id())] = session;
116 });
117
118 server->set_disconnection_callback(
119 [&sessions, &sessions_mutex](std::string_view session_id) {
120 std::lock_guard<std::mutex> lock(sessions_mutex);
121 sessions.erase(std::string(session_id));
122 });
123
124 server->set_receive_callback(
125 [&sessions, &sessions_mutex](std::string_view session_id,
126 const std::vector<uint8_t>& data) {
127 std::lock_guard<std::mutex> lock(sessions_mutex);
128 auto it = sessions.find(std::string(session_id));
129 if (it != sessions.end()) {
130 it->second->send(std::vector<uint8_t>(data));
131 }
132 });
133
134 auto server_result = server->start(port);
135 if (server_result.is_err()) {
136 std::cerr << "Server start failed: " << server_result.error().message << std::endl;
137 return 1;
138 }
139 std::cout << "Echo server running on port " << port << std::endl;
140 std::this_thread::sleep_for(std::chrono::milliseconds(100));
141
142 // --- Example 1: Full connection_observer ---
143 std::cout << "\n--- Example 1: Full connection_observer ---" << std::endl;
144 {
145 auto client = tcp.create_client({
146 .host = "127.0.0.1",
147 .port = port,
148 .client_id = "ObserverClient",
149 });
150
151 auto observer = std::make_shared<chat_observer>("FullObserver");
152 client->set_observer(observer);
153
154 auto result = client->start("127.0.0.1", port);
155 if (result.is_ok()) {
156 std::this_thread::sleep_for(std::chrono::milliseconds(200));
157
158 std::string msg = "Hello via observer!";
159 std::vector<uint8_t> data(msg.begin(), msg.end());
160 client->send(std::move(data));
161
162 std::this_thread::sleep_for(std::chrono::milliseconds(500));
163 std::cout << "Messages received: " << observer->message_count() << std::endl;
164 }
165
166 client->stop();
167 std::this_thread::sleep_for(std::chrono::milliseconds(100));
168 }
169
170 // --- Example 2: callback_adapter (functional style) ---
171 std::cout << "\n--- Example 2: callback_adapter ---" << std::endl;
172 {
173 auto client = tcp.create_client({
174 .host = "127.0.0.1",
175 .port = port,
176 .client_id = "AdapterClient",
177 });
178
179 auto adapter = std::make_shared<interfaces::callback_adapter>();
180 adapter->on_connected([]() {
181 std::cout << "[Adapter] Connected!" << std::endl;
182 })
183 .on_receive([](std::span<const uint8_t> data) {
184 std::string msg(data.begin(), data.end());
185 std::cout << "[Adapter] Received: " << msg << std::endl;
186 })
187 .on_disconnected([](std::optional<std::string_view> reason) {
188 std::cout << "[Adapter] Disconnected." << std::endl;
189 })
190 .on_error([](std::error_code ec) {
191 std::cerr << "[Adapter] Error: " << ec.message() << std::endl;
192 });
193
194 client->set_observer(adapter);
195
196 auto result = client->start("127.0.0.1", port);
197 if (result.is_ok()) {
198 std::this_thread::sleep_for(std::chrono::milliseconds(200));
199
200 std::string msg = "Hello via callback_adapter!";
201 std::vector<uint8_t> data(msg.begin(), msg.end());
202 client->send(std::move(data));
203
204 std::this_thread::sleep_for(std::chrono::milliseconds(500));
205 }
206
207 client->stop();
208 std::this_thread::sleep_for(std::chrono::milliseconds(100));
209 }
210
211 // --- Cleanup ---
212 server->stop();
213 std::cout << "\n=== Observer pattern example completed ===" << std::endl;
214
215 return 0;
216}
Custom observer that handles all connection events.
auto on_disconnected(std::optional< std::string_view > reason) -> void override
Called when the connection is closed.
auto on_connected() -> void override
Called when the connection is established.
auto on_error(std::error_code ec) -> void override
Called when an error occurs.
chat_observer(const std::string &name)
auto message_count() const -> int
auto on_receive(std::span< const uint8_t > data) -> void override
Called when data is received from the server.
Simplified facade for creating TCP clients and servers.
Definition tcp_facade.h:95
Observer interface for client connection events.
No-op implementation of connection_observer.
Partial observer that only handles receive events.
auto on_receive(std::span< const uint8_t > data) -> void override
Called when data is received from the server.
Observer interface for connection state change notifications.
Session interface representing an active client-server connection.
Main namespace for all Network System components.
int main()
Simplified facade for creating TCP clients and servers.