git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce

subrepo:
  subdir:   "deps/juce"
  merged:   "b13f9084e"
upstream:
  origin:   "https://github.com/essej/JUCE.git"
  branch:   "sono6good"
  commit:   "b13f9084e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
This commit is contained in:
essej
2022-04-18 17:51:22 -04:00
parent 63e175fee6
commit 25bd5d8adb
3210 changed files with 1045392 additions and 0 deletions

View File

@ -0,0 +1,77 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
void Analytics::addDestination (AnalyticsDestination* destination)
{
destinations.add (destination);
}
OwnedArray<AnalyticsDestination>& Analytics::getDestinations()
{
return destinations;
}
void Analytics::setUserId (String newUserId)
{
userId = newUserId;
}
void Analytics::setUserProperties (StringPairArray properties)
{
userProperties = properties;
}
void Analytics::logEvent (const String& eventName,
const StringPairArray& parameters,
int eventType)
{
if (! isSuspended)
{
AnalyticsDestination::AnalyticsEvent event
{
eventName,
eventType,
Time::getMillisecondCounter(),
parameters,
userId,
userProperties
};
for (auto* destination : destinations)
destination->logEvent (event);
}
}
void Analytics::setSuspended (bool shouldBeSuspended)
{
isSuspended = shouldBeSuspended;
}
JUCE_IMPLEMENT_SINGLETON (Analytics)
}

View File

@ -0,0 +1,116 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A singleton class to manage analytics data.
Use an Analytics object to manage sending analytics data to one or more
AnalyticsDestinations.
@see AnalyticsDestination, ThreadedAnalyticsDestination,
AnalyticsDestination::AnalyticsEvent
@tags{Analytics}
*/
class JUCE_API Analytics : public DeletedAtShutdown
{
public:
//==============================================================================
/** Adds an AnalyticsDestination to the list of AnalyticsDestinations
managed by this Analytics object.
The Analytics class will take ownership of the AnalyticsDestination
passed to this function.
@param destination the AnalyticsDestination to manage
*/
void addDestination (AnalyticsDestination* destination);
/** Returns the array of AnalyticsDestinations managed by this class.
If you have added any subclasses of ThreadedAnalyticsDestination to
this class then you can remove them from this list to force them to
flush any pending events.
*/
OwnedArray<AnalyticsDestination>& getDestinations();
/** Sets a user ID that will be added to all AnalyticsEvents sent to
AnalyticsDestinations.
@param newUserId the userId to add to AnalyticsEvents
*/
void setUserId (String newUserId);
/** Sets some user properties that will be added to all AnalyticsEvents sent
to AnalyticsDestinations.
@param properties the userProperties to add to AnalyticsEvents
*/
void setUserProperties (StringPairArray properties);
/** Sends an AnalyticsEvent to all AnalyticsDestinations.
The AnalyticsEvent will be timestamped, and will have the userId and
userProperties populated by values previously set by calls to
setUserId and setUserProperties. The name, parameters and type will be
populated by the arguments supplied to this function.
@param eventName the event name
@param parameters the event parameters
@param eventType (optional) an integer to indicate the event
type, which will be set to 0 if not supplied.
*/
void logEvent (const String& eventName, const StringPairArray& parameters, int eventType = 0);
/** Suspends analytics submissions to AnalyticsDestinations.
@param shouldBeSuspended if event submission should be suspended
*/
void setSuspended (bool shouldBeSuspended);
#ifndef DOXYGEN
JUCE_DECLARE_SINGLETON (Analytics, false)
#endif
private:
//==============================================================================
Analytics() = default;
~Analytics() override { clearSingletonInstance(); }
String userId;
StringPairArray userProperties;
bool isSuspended = false;
OwnedArray<AnalyticsDestination> destinations;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Analytics)
};
} // namespace juce

View File

@ -0,0 +1,60 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ButtonTracker::ButtonTracker (Button& buttonToTrack,
const String& triggeredEventName,
const StringPairArray& triggeredEventParameters,
int triggeredEventType)
: button (buttonToTrack),
eventName (triggeredEventName),
eventParameters (triggeredEventParameters),
eventType (triggeredEventType)
{
button.addListener (this);
}
ButtonTracker::~ButtonTracker()
{
button.removeListener (this);
}
void ButtonTracker::buttonClicked (Button* b)
{
if (b == &button)
{
auto params = eventParameters;
if (button.getClickingTogglesState())
params.set ("ButtonState", button.getToggleState() ? "On" : "Off");
Analytics::getInstance()->logEvent (eventName, params, eventType);
}
}
} // namespace juce

View File

@ -0,0 +1,79 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A class that automatically sends analytics events to the Analytics singleton
when a button is clicked.
@see Analytics, AnalyticsDestination::AnalyticsEvent
@tags{Analytics}
*/
class JUCE_API ButtonTracker : private Button::Listener
{
public:
//==============================================================================
/**
Creating one of these automatically sends analytics events to the Analytics
singleton when the corresponding button is clicked.
The name and parameters of the analytics event will be populated from the
variables supplied here. If clicking changes the button's state then the
parameters will have a {"ButtonState", "On"/"Off"} entry added.
@param buttonToTrack the button to track
@param triggeredEventName the name of the generated event
@param triggeredEventParameters the parameters to add to the generated
event
@param triggeredEventType (optional) an integer to indicate the event
type, which will be set to 0 if not supplied.
@see Analytics, AnalyticsDestination::AnalyticsEvent
*/
ButtonTracker (Button& buttonToTrack,
const String& triggeredEventName,
const StringPairArray& triggeredEventParameters = {},
int triggeredEventType = 0);
/** Destructor. */
~ButtonTracker() override;
private:
/** @internal */
void buttonClicked (Button*) override;
Button& button;
const String eventName;
const StringPairArray eventParameters;
const int eventType;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonTracker)
};
} // namespace juce

View File

@ -0,0 +1,97 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
An interface for handling analytics events collected by an Analytics object.
For basic analytics logging you can implement this interface and add your
class to an Analytics object.
For more advanced logging you may want to subclass
ThreadedAnalyticsDestination instead, which is more suitable for interacting
with web servers and other time consuming destinations.
@see Analytics, ThreadedAnalyticsDestination
@tags{Analytics}
*/
struct JUCE_API AnalyticsDestination
{
/** Contains information about an event to be logged. */
struct AnalyticsEvent
{
/** The name of the event. */
String name;
/** An optional integer representing the type of the event. You can use
this to indicate if the event was a screenview, session start,
exception, etc.
*/
int eventType;
/**
The timestamp of the event.
Timestamps are automatically applied by an Analytics object and are
derived from Time::getMillisecondCounter(). As such these timestamps
do not represent absolute times, but relative timings of events for
each user in each session will be accurate.
*/
uint32 timestamp;
/** The parameters of the event. */
StringPairArray parameters;
/** The user ID associated with the event. */
String userID;
/** Properties associated with the user. */
StringPairArray userProperties;
};
/** Constructor. */
AnalyticsDestination() = default;
/** Destructor. */
virtual ~AnalyticsDestination() = default;
/**
When an AnalyticsDestination is added to an Analytics object this method
is called when an analytics event is triggered from the Analytics
object.
Override this method to log the event information somewhere useful.
*/
virtual void logEvent (const AnalyticsEvent& event) = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnalyticsDestination)
};
} // namespace juce

View File

@ -0,0 +1,291 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ThreadedAnalyticsDestination::ThreadedAnalyticsDestination (const String& threadName)
: dispatcher (threadName, *this)
{}
ThreadedAnalyticsDestination::~ThreadedAnalyticsDestination()
{
// If you hit this assertion then the analytics thread has not been shut down
// before this class is destroyed. Call stopAnalyticsThread() in your destructor!
jassert (! dispatcher.isThreadRunning());
}
void ThreadedAnalyticsDestination::setBatchPeriod (int newBatchPeriodMilliseconds)
{
dispatcher.batchPeriodMilliseconds = newBatchPeriodMilliseconds;
}
void ThreadedAnalyticsDestination::logEvent (const AnalyticsEvent& event)
{
dispatcher.addToQueue (event);
}
void ThreadedAnalyticsDestination::startAnalyticsThread (int initialBatchPeriodMilliseconds)
{
setBatchPeriod (initialBatchPeriodMilliseconds);
dispatcher.startThread();
}
void ThreadedAnalyticsDestination::stopAnalyticsThread (int timeout)
{
dispatcher.signalThreadShouldExit();
stopLoggingEvents();
dispatcher.stopThread (timeout);
if (dispatcher.eventQueue.size() > 0)
saveUnloggedEvents (dispatcher.eventQueue);
}
ThreadedAnalyticsDestination::EventDispatcher::EventDispatcher (const String& dispatcherThreadName,
ThreadedAnalyticsDestination& destination)
: Thread (dispatcherThreadName),
parent (destination)
{}
void ThreadedAnalyticsDestination::EventDispatcher::run()
{
// We may have inserted some events into the queue (on the message thread)
// before this thread has started, so make sure the old events are at the
// front of the queue.
{
std::deque<AnalyticsEvent> restoredEventQueue;
parent.restoreUnloggedEvents (restoredEventQueue);
const ScopedLock lock (queueAccess);
for (auto rit = restoredEventQueue.rbegin(); rit != restoredEventQueue.rend(); ++rit)
eventQueue.push_front (*rit);
}
const int maxBatchSize = parent.getMaximumBatchSize();
while (! threadShouldExit())
{
{
const ScopedLock lock (queueAccess);
const auto numEventsInBatch = eventsToSend.size();
const auto freeBatchCapacity = maxBatchSize - numEventsInBatch;
if (freeBatchCapacity > 0)
{
const auto numNewEvents = (int) eventQueue.size() - numEventsInBatch;
if (numNewEvents > 0)
{
const auto numEventsToAdd = jmin (numNewEvents, freeBatchCapacity);
const auto newBatchSize = numEventsInBatch + numEventsToAdd;
for (auto i = numEventsInBatch; i < newBatchSize; ++i)
eventsToSend.add (eventQueue[(size_t) i]);
}
}
}
const auto submissionTime = Time::getMillisecondCounter();
if (! eventsToSend.isEmpty())
{
if (parent.logBatchedEvents (eventsToSend))
{
const ScopedLock lock (queueAccess);
for (auto i = 0; i < eventsToSend.size(); ++i)
eventQueue.pop_front();
eventsToSend.clearQuick();
}
}
while (Time::getMillisecondCounter() - submissionTime < (uint32) batchPeriodMilliseconds.get())
{
if (threadShouldExit())
return;
Thread::sleep (100);
}
}
}
void ThreadedAnalyticsDestination::EventDispatcher::addToQueue (const AnalyticsEvent& event)
{
const ScopedLock lock (queueAccess);
eventQueue.push_back (event);
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
namespace DestinationTestHelpers
{
//==============================================================================
struct BasicDestination : public ThreadedAnalyticsDestination
{
BasicDestination (std::deque<AnalyticsEvent>& loggedEvents,
std::deque<AnalyticsEvent>& unloggedEvents)
: ThreadedAnalyticsDestination ("ThreadedAnalyticsDestinationTest"),
loggedEventQueue (loggedEvents),
unloggedEventStore (unloggedEvents)
{
startAnalyticsThread (20);
}
~BasicDestination() override
{
stopAnalyticsThread (1000);
}
int getMaximumBatchSize() override
{
return 5;
}
void saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave) override
{
unloggedEventStore = eventsToSave;
}
void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) override
{
restoredEventQueue = unloggedEventStore;
}
bool logBatchedEvents (const Array<AnalyticsEvent>& events) override
{
jassert (events.size() <= getMaximumBatchSize());
if (loggingIsEnabled)
{
const ScopedLock lock (eventQueueChanging);
for (auto& event : events)
loggedEventQueue.push_back (event);
return true;
}
return false;
}
void stopLoggingEvents() override {}
void setLoggingEnabled (bool shouldLogEvents)
{
loggingIsEnabled = shouldLogEvents;
}
std::deque<AnalyticsEvent>& loggedEventQueue;
std::deque<AnalyticsEvent>& unloggedEventStore;
bool loggingIsEnabled = true;
CriticalSection eventQueueChanging;
};
}
//==============================================================================
struct ThreadedAnalyticsDestinationTests : public UnitTest
{
ThreadedAnalyticsDestinationTests()
: UnitTest ("ThreadedAnalyticsDestination", UnitTestCategories::analytics)
{}
void compareEventQueues (const std::deque<AnalyticsDestination::AnalyticsEvent>& a,
const std::deque<AnalyticsDestination::AnalyticsEvent>& b)
{
const auto numEntries = a.size();
expectEquals ((int) b.size(), (int) numEntries);
for (size_t i = 0; i < numEntries; ++i)
{
expectEquals (a[i].name, b[i].name);
expect (a[i].timestamp == b[i].timestamp);
}
}
void runTest() override
{
std::deque<AnalyticsDestination::AnalyticsEvent> testEvents;
for (int i = 0; i < 7; ++i)
testEvents.push_back ({ String (i), 0, Time::getMillisecondCounter(), {}, "TestUser", {} });
std::deque<AnalyticsDestination::AnalyticsEvent> loggedEvents, unloggedEvents;
beginTest ("New events");
{
DestinationTestHelpers::BasicDestination destination (loggedEvents, unloggedEvents);
for (auto& event : testEvents)
destination.logEvent (event);
size_t waitTime = 0, numLoggedEvents = 0;
while (numLoggedEvents < testEvents.size())
{
if (waitTime > 4000)
{
expect (waitTime < 4000);
break;
}
Thread::sleep (40);
waitTime += 40;
const ScopedLock lock (destination.eventQueueChanging);
numLoggedEvents = loggedEvents.size();
}
}
compareEventQueues (loggedEvents, testEvents);
expect (unloggedEvents.size() == 0);
loggedEvents.clear();
beginTest ("Unlogged events");
{
DestinationTestHelpers::BasicDestination destination (loggedEvents, unloggedEvents);
destination.setLoggingEnabled (false);
for (auto& event : testEvents)
destination.logEvent (event);
}
compareEventQueues (unloggedEvents, testEvents);
expect (loggedEvents.size() == 0);
}
};
static ThreadedAnalyticsDestinationTests threadedAnalyticsDestinationTests;
#endif
} // namespace juce

View File

@ -0,0 +1,217 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
A base class for dispatching analytics events on a dedicated thread.
This class is particularly useful for sending analytics events to a web
server without blocking the message thread. It can also save (and restore)
events that were not dispatched so no information is lost when an internet
connection is absent or something else prevents successful logging.
Once startAnalyticsThread is called the logBatchedEvents method is
periodically invoked on an analytics thread, with the period determined by
calls to setBatchPeriod. Here events are grouped together into batches, with
the maximum batch size set by the implementation of getMaximumBatchSize.
It's important to call stopAnalyticsThread in the destructor of your
subclass (or before then) to give the analytics thread time to shut down.
Calling stopAnalyticsThread will, in turn, call stopLoggingEvents, which
you should use to terminate the currently running logBatchedEvents call.
@see Analytics, AnalyticsDestination, AnalyticsDestination::AnalyticsEvent
@tags{Analytics}
*/
class JUCE_API ThreadedAnalyticsDestination : public AnalyticsDestination
{
public:
//==============================================================================
/**
Creates a ThreadedAnalyticsDestination.
@param threadName used to identify the analytics
thread in debug builds
*/
ThreadedAnalyticsDestination (const String& threadName = "Analytics thread");
/** Destructor. */
~ThreadedAnalyticsDestination() override;
//==============================================================================
/**
Override this method to provide the maximum batch size you can handle in
your subclass.
Calls to logBatchedEvents will contain no more than this number of events.
*/
virtual int getMaximumBatchSize() = 0;
/**
This method will be called periodically on the analytics thread.
If this method returns false then the subsequent call of this function will
contain the same events as previous call, plus any new events that have been
generated in the period between calls. The order of events will not be
changed. This allows you to retry logging events until they are logged
successfully.
@param events a list of events to be logged
@returns if the events were successfully logged
*/
virtual bool logBatchedEvents (const Array<AnalyticsEvent>& events) = 0;
/**
You must always call stopAnalyticsThread in the destructor of your subclass
(or before then) to give the analytics thread time to shut down.
Calling stopAnalyticsThread triggers a call to this method. At this point
you are guaranteed that logBatchedEvents has been called for the last time
and you should make sure that the current call to logBatchedEvents finishes
as quickly as possible. This method and a subsequent call to
saveUnloggedEvents must both complete before the timeout supplied to
stopAnalyticsThread.
In a normal use case stopLoggingEvents will be called on the message thread
from the destructor of your ThreadedAnalyticsDestination subclass, and must
stop the logBatchedEvents method which is running on the analytics thread.
@see stopAnalyticsThread
*/
virtual void stopLoggingEvents() = 0;
//==============================================================================
/**
Call this to set the period between logBatchedEvents invocations.
This method is thread safe and can be used to implements things like
exponential backoff in logBatchedEvents calls.
@param newSubmissionPeriodMilliseconds the new submission period to
use in milliseconds
*/
void setBatchPeriod (int newSubmissionPeriodMilliseconds);
/**
Adds an event to the queue, which will ultimately be submitted to
logBatchedEvents.
This method is thread safe.
@param event the analytics event to add to the queue
*/
void logEvent (const AnalyticsEvent& event) override final;
protected:
//==============================================================================
/**
Starts the analytics thread, with an initial event batching period.
@param initialBatchPeriodMilliseconds the initial event batching period
in milliseconds
*/
void startAnalyticsThread (int initialBatchPeriodMilliseconds);
//==============================================================================
/**
Triggers the shutdown of the analytics thread.
You must call this method in the destructor of your subclass (or before
then) to give the analytics thread time to shut down.
This method invokes stopLoggingEvents and you should ensure that both the
analytics thread and a call to saveUnloggedEvents are able to finish before
the supplied timeout. This timeout is important because on platforms like
iOS an app is killed if it takes too long to shut down.
@param timeoutMilliseconds the number of milliseconds before
the analytics thread is forcibly
terminated
*/
void stopAnalyticsThread (int timeoutMilliseconds);
private:
//==============================================================================
/**
This method will be called when the analytics thread is shut down,
giving you the chance to save any analytics events that could not be
logged. Once saved these events can be put back into the queue of events
when the ThreadedAnalyticsDestination is recreated via
restoreUnloggedEvents.
This method should return as quickly as possible, as both
stopLoggingEvents and this method need to complete inside the timeout
set in stopAnalyticsThread.
@param eventsToSave the events that could not be logged
@see stopAnalyticsThread, stopLoggingEvents, restoreUnloggedEvents
*/
virtual void saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave) = 0;
/**
The counterpart to saveUnloggedEvents.
Events added to the event queue provided by this method will be the
first events supplied to logBatchedEvents calls. Use this method to
restore any unlogged events previously stored in a call to
saveUnloggedEvents.
This method is called on the analytics thread.
@param restoredEventQueue place restored events into this queue
@see saveUnloggedEvents
*/
virtual void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) = 0;
struct EventDispatcher : public Thread
{
EventDispatcher (const String& threadName, ThreadedAnalyticsDestination&);
void run() override;
void addToQueue (const AnalyticsEvent&);
ThreadedAnalyticsDestination& parent;
std::deque<AnalyticsEvent> eventQueue;
CriticalSection queueAccess;
Atomic<int> batchPeriodMilliseconds { 1000 };
Array<AnalyticsEvent> eventsToSend;
};
const String destinationName;
EventDispatcher dispatcher;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadedAnalyticsDestination)
};
} // namespace juce

View File

@ -0,0 +1,39 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#ifdef JUCE_ANALYTICS_H_INCLUDED
/* When you add this cpp file to your project, you mustn't include it in a file where you've
already included any other headers - just put it inside a file on its own, possibly with your config
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
header files that the compiler may be using.
*/
#error "Incorrect use of JUCE cpp file"
#endif
#include "juce_analytics.h"
#include "destinations/juce_ThreadedAnalyticsDestination.cpp"
#include "analytics/juce_Analytics.cpp"
#include "analytics/juce_ButtonTracker.cpp"

View File

@ -0,0 +1,60 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*******************************************************************************
The block below describes the properties of this module, and is read by
the Projucer to automatically generate project code that uses it.
For details about the syntax and how to create or use a module, see the
JUCE Module Format.md file.
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_analytics
vendor: juce
version: 6.1.2
name: JUCE analytics classes
description: Classes to collect analytics and send to destinations
website: http://www.juce.com/juce
license: GPL/Commercial
minimumCppStandard: 14
dependencies: juce_gui_basics
END_JUCE_MODULE_DECLARATION
*******************************************************************************/
#pragma once
#define JUCE_ANALYTICS_H_INCLUDED
#include <juce_gui_basics/juce_gui_basics.h>
#include "destinations/juce_AnalyticsDestination.h"
#include "destinations/juce_ThreadedAnalyticsDestination.h"
#include "analytics/juce_Analytics.h"
#include "analytics/juce_ButtonTracker.h"