20#include "JuceHeader.h"
28juce::uint32 CelloMagicIpcNumber { 0x000C3110 };
33template <>
struct VariantConverter<cello::IpcServerStatus>
35 static cello::IpcServerStatus fromVar (
const var& v) {
return static_cast<cello::IpcServerStatus
> (int (v)); }
37 static var toVar (
const cello::IpcServerStatus& t) {
return static_cast<int> (t); }
44IpcClient::IpcClient (Object& objectToWatch, UpdateType updateType,
const juce::String& hostName,
int portNum,
45 const juce::String& pipeName,
int msTimeout, Object* state)
46: juce::InterprocessConnection { true, CelloMagicIpcNumber }
47, juce::ValueTreeSynchroniser { objectToWatch }
48, UpdateQueue { objectToWatch, nullptr }
49, clientProperties { objectToWatch.getType ().toString (), state }
50, update { updateType }
54, timeout { msTimeout }
58 jassert ((update & UpdateType::send) || (update & UpdateType::receive));
60 jassert (!(update & UpdateType::fullUpdateOnConnect) ||
61 ((update & UpdateType::fullUpdateOnConnect) && (update & UpdateType::send)));
65 UpdateType updateType,
Object* state)
66:
IpcClient (objectToWatch, updateType, hostName, portNum,
"", msTimeout, state)
68 jassert (host.isNotEmpty ());
73:
IpcClient (objectToWatch, updateType,
"", 0, pipeName, msTimeout, state)
75 jassert (pipe.isNotEmpty ());
78IpcClient::~IpcClient ()
85 if (host.isNotEmpty ())
89 return connectToSocket (host, port, timeout);
92 if (pipe.isNotEmpty ())
98 return createPipe (pipe, timeout,
true);
100 return connectToPipe (pipe, timeout);
102 return createPipe (pipe, timeout,
false);
114void IpcClient::connectionMade ()
116 clientProperties.connected =
true;
117 if (update & UpdateType::fullUpdateOnConnect)
118 sendFullSyncCallback ();
121void IpcClient::connectionLost ()
123 clientProperties.connected =
false;
126void IpcClient::messageReceived (
const juce::MemoryBlock& message)
128 if (update & UpdateType::receive)
131 pushUpdate (juce::MemoryBlock { message });
132 clientProperties.rxCount++;
135void IpcClient::stateChanged (
const void* encodedChange,
size_t encodedSize)
137 if ((update & UpdateType::send) && (clientProperties.connected))
139 if (updateData != SyncData { encodedChange, encodedSize })
141 sendMessage ({ encodedChange, encodedSize });
142 clientProperties.txCount++;
147void IpcClient::startUpdate (
void* data,
size_t size)
149 updateData = SyncData { data, size };
152void IpcClient::endUpdate ()
154 updateData = SyncData {};
159IpcServerProperties::IpcServerProperties (
const juce::String& path,
Object* state)
170 status = IpcServerStatus::alreadyRunning;
173 bindAddress = address;
176 portNumber = portNum;
183 status = IpcServerStatus::alreadyStopped;
191IpcServer::IpcServer (
Object& sync, IpcClient::UpdateType updateType,
const juce::String& statePath,
Object* state)
193, update { updateType }
194, serverProperties { statePath, state }
199 [
this] (
const juce::Identifier& )
201 if (serverProperties.portNumber > 0)
202 startServer (serverProperties.portNumber, serverProperties.bindAddress);
208IpcServer::~IpcServer ()
213 connections.clear ();
218 if (serverProperties.running)
220 serverProperties.status = IpcServerStatus::alreadyRunning;
224 if (beginWaitingForSocket (portNumber, bindAddress))
226 serverProperties.running =
true;
227 serverProperties.status = IpcServerStatus::startedOkay;
231 serverProperties.running =
false;
232 serverProperties.status = IpcServerStatus::errorStarting;
238 if (!serverProperties.running)
240 serverProperties.status = IpcServerStatus::alreadyStopped;
248 serverProperties.running =
false;
249 serverProperties.status = IpcServerStatus::stoppedOkay;
258 auto client { std::make_unique<IpcClient> (syncObject,
"", 0, 0, update, &serverProperties) };
259 juce::InterprocessConnection* connection { client.get () };
260 connections.push_back (std::move (client));
267#include "test/test_cello_ipc.inl"
IpcClient(Object &objectToWatch, const juce::String &hostName, int portNum, int msTimeout, UpdateType updateType, Object *state=nullptr)
Construct a new Ipc Client object that connects using sockets.
Definition cello_ipc.cpp:64
bool connect(ConnectOptions option=ConnectOptions::noOptions)
Attempt to make a connection to another IpcClient running in another process.
Definition cello_ipc.cpp:83
ConnectOptions
Definition cello_ipc.h:62
@ mustExist
pipe must already exist, fail if it doesn't
Definition cello_ipc.h:65
@ noOptions
default, used for sockets, which have no options.
Definition cello_ipc.h:63
@ createIfNeeded
If pipe exists, use it, otherwise create.
Definition cello_ipc.h:66
@ createOrFail
create the pipe, fail if we couldn't
Definition cello_ipc.h:64
bool startServer(int portNumber, const juce::String &bindAddress=juce::String())
Launch the thread that starts listening for incoming socket connections.
Definition cello_ipc.cpp:216
bool stopServer()
Stop the server.
Definition cello_ipc.cpp:236
juce::InterprocessConnection * createConnectionObject() override
When we get a connection, the base server class will call this so that we can create and return an in...
Definition cello_ipc.cpp:253
Definition cello_object.h:34
void onPropertyChange(const juce::Identifier &id, PropertyUpdateFn callback)
Install (or clear) a function to be called when one of this Object's properties changes....
Definition cello_object.cpp:255
void forceUpdate(bool shouldForceUpdate)
If passed true, any call that sets any Value property on this Object will result in a property change...
Definition cello_update_source.h:39
void stopServer()
Tell the server object we're controlling to stop.
Definition cello_ipc.cpp:179
void startServer(int portNum, const juce::String &address=juce::String())
Tell the server object we're controlling to start on the specified port (and optionally which address...
Definition cello_ipc.cpp:166