Skip to content

Commit

Permalink
New Ice/bidir demo for C++ (#295)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardnormier authored Feb 12, 2025
1 parent 11cf8a8 commit 8a65ec9
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 349 deletions.
27 changes: 27 additions & 0 deletions cpp/Ice/bidir/AlarmClock.ice
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) ZeroC, Inc.

#pragma once

module EarlyRiser
{
/// Indicates the button pressed when the alarm rang.
enum ButtonPressed { Snooze, Stop }

/// Represents a simple alarm clock. It's the "callback" in this demo, and it's implemented by the client.
interface AlarmClock
{
/// Rings the alarm clock.
/// @param message The message to display.
/// @return The button pressed by the user.
ButtonPressed ring(string message);
}

/// Represents the wake up service provided by the server.
interface WakeUpService
{
/// Schedules a call to the caller's {@link AlarmClock::ring} at the specified time.
/// @param timeStamp The time to ring the alarm clock. It's encoded as the number of ticks (100 nanoseconds)
/// since January 1, 0001 00:00:00 UTC in the Gregorian calendar.
void wakeMeUp(long timeStamp);
}
}
77 changes: 77 additions & 0 deletions cpp/Ice/bidir/BidirWakeUpService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) ZeroC, Inc.

#include "BidirWakeUpService.h"

#include <algorithm>
#include <iostream>

using namespace EarlyRiser;
using namespace std;

namespace
{
// Converts a time stamp to a time point.
chrono::system_clock::time_point toTimePoint(int64_t timeStamp)
{
const int daysBeforeEpoch = 719162;

chrono::microseconds timePointMicro{timeStamp / 10}; // timeStamp is in ticks (100 nanoseconds)
return chrono::system_clock::time_point{timePointMicro - daysBeforeEpoch * 24h};
}
}

Server::BidirWakeUpService::~BidirWakeUpService()
{
// Waits for all outstanding tasks to complete.
for (auto& task : _tasks)
{
task.wait();
}
}

void
Server::BidirWakeUpService::wakeMeUp(int64_t timeStamp, const Ice::Current& current)
{
// With C++20, we'll be able to print the time point easily--but not with C++17.
cout << "Dispatching wakeMeUp request { timeStamp = " << timeStamp << " ticks }" << endl;

chrono::system_clock::time_point timePoint = toTimePoint(timeStamp);

Ice::ConnectionPtr connection = current.con; // The connection from the client to the server.
if (!connection)
{
// Should never happen, but in case it does, the Ice runtime will send an Ice::UnknownException to the client.
throw std::invalid_argument{"BidirWakeUpService does not support collocated calls"};
}

// Create a proxy to the client's alarm clock. This connection-bound proxy is called a "fixed proxy".
auto alarmClock = connection->createProxy<AlarmClockPrx>(Ice::stringToIdentity("alarmClock"));

// Schedule a wake-up call in a background task.
_tasks.emplace_back(std::async(
std::launch::async,
[alarmClock = std::move(alarmClock), timePoint]()
{
// Sleep until the specified time point.
this_thread::sleep_until(timePoint);

// First ring.
ButtonPressed buttonPressed = alarmClock->ring("It's time to wake up!");

// Keep ringing every 10 seconds until the user presses the stop button.
while (buttonPressed == ButtonPressed::Snooze)
{
this_thread::sleep_for(10s);
buttonPressed = alarmClock->ring("No more snoozing!");
}
}));

// We don't want the _tasks vector to grow forever so remove all completed tasks here, without waiting.
// TODO: switch to std::erase_if when we can use C++20.
_tasks.erase(
std::remove_if(
_tasks.begin(),
_tasks.end(),
[](const auto& task) { return task.wait_for(std::chrono::seconds(0)) == std::future_status::ready; }),
_tasks.end());
}
28 changes: 28 additions & 0 deletions cpp/Ice/bidir/BidirWakeUpService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) ZeroC, Inc.

#ifndef BIDIR_WAKE_UP_SERVICE_H
#define BIDIR_WAKE_UP_SERVICE_H

#include "AlarmClock.h"

#include <future>
#include <vector>

namespace Server
{
/// BidirWakeUpService is an Ice servant that implements Slice interface WakeUpService.
class BidirWakeUpService : public EarlyRiser::WakeUpService
{
public:
// Waits for all outstanding tasks to complete.
~BidirWakeUpService() override;

// Implements the pure virtual function in the base class (WakeUpService) generated by the Slice compiler.
void wakeMeUp(std::int64_t timeStamp, const Ice::Current&) override;

private:
std::vector<std::future<void>> _tasks;
};
}

#endif
4 changes: 2 additions & 2 deletions cpp/Ice/bidir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ project(bidir CXX)

include(../../cmake/common.cmake)

add_executable(client Client.cpp Callback.ice)
add_executable(client Client.cpp MockAlarmClock.h MockAlarmClock.cpp AlarmClock.ice)
slice2cpp_generate(client)
target_link_libraries(client Ice::Ice)

add_executable(server Server.cpp CallbackI.cpp CallbackI.h Callback.ice)
add_executable(server Server.cpp BidirWakeUpService.h BidirWakeUpService.cpp AlarmClock.ice)
slice2cpp_generate(server)
target_link_libraries(server Ice::Ice)
16 changes: 0 additions & 16 deletions cpp/Ice/bidir/Callback.ice

This file was deleted.

99 changes: 0 additions & 99 deletions cpp/Ice/bidir/CallbackI.cpp

This file was deleted.

28 changes: 0 additions & 28 deletions cpp/Ice/bidir/CallbackI.h

This file was deleted.

Loading

0 comments on commit 8a65ec9

Please sign in to comment.