From e1e41708af30edf7ae6298110ed48437bb0bb161 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 18 May 2021 16:33:16 +0200 Subject: [PATCH] input/LastInputStream: new class --- src/input/LastInputStream.cxx | 45 ++++++++++++++++++ src/input/LastInputStream.hxx | 86 +++++++++++++++++++++++++++++++++++ src/input/meson.build | 1 + 3 files changed, 132 insertions(+) create mode 100644 src/input/LastInputStream.cxx create mode 100644 src/input/LastInputStream.hxx diff --git a/src/input/LastInputStream.cxx b/src/input/LastInputStream.cxx new file mode 100644 index 000000000..40bd5ccc2 --- /dev/null +++ b/src/input/LastInputStream.cxx @@ -0,0 +1,45 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "LastInputStream.hxx" +#include "InputStream.hxx" + +#include + +LastInputStream::LastInputStream(EventLoop &event_loop) noexcept + :close_timer(event_loop, BIND_THIS_METHOD(OnCloseTimer)) +{ +} + +LastInputStream::~LastInputStream() noexcept = default; + +void +LastInputStream::Close() noexcept +{ + is.reset(); + close_timer.Cancel(); +} + +void +LastInputStream::OnCloseTimer() noexcept +{ + assert(is); + + is.reset(); +} diff --git a/src/input/LastInputStream.hxx b/src/input/LastInputStream.hxx new file mode 100644 index 000000000..2121772a0 --- /dev/null +++ b/src/input/LastInputStream.hxx @@ -0,0 +1,86 @@ +/* + * Copyright 2003-2021 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_LAST_INPUT_STREAM_HXX +#define MPD_LAST_INPUT_STREAM_HXX + +#include "Ptr.hxx" +#include "thread/Mutex.hxx" +#include "event/TimerEvent.hxx" + +#include + +/** + * A helper class which maintains an #InputStream that is opened once + * and may be reused later for some time. It will be closed + * automatically after some time. + * + * This class is not thread-safe. All methods must be called on the + * thread which runs the #EventLoop. + */ +class LastInputStream { + std::string uri; + + Mutex mutex; + + InputStreamPtr is; + + TimerEvent close_timer; + +public: + explicit LastInputStream(EventLoop &event_loop) noexcept; + ~LastInputStream() noexcept; + + /** + * Open an #InputStream instance with the given opener + * function, but returns the cached instance if it matches. + * + * This object keeps owning the #InputStream; the caller shall + * not close it. + */ + template + InputStream *Open(U &&new_uri, O &&open) { + if (new_uri == uri) { + if (is) + /* refresh the timeout */ + ScheduleClose(); + + return is.get(); + } + + is.reset(); + close_timer.Cancel(); + + is = open(new_uri, mutex); + uri = std::forward(new_uri); + ScheduleClose(); + return is.get(); + } + + void Close() noexcept; + +private: + void ScheduleClose() noexcept { + close_timer.Schedule(std::chrono::seconds(20)); + } + + void OnCloseTimer() noexcept; +}; + +#endif diff --git a/src/input/meson.build b/src/input/meson.build index 374b5704e..03795b21b 100644 --- a/src/input/meson.build +++ b/src/input/meson.build @@ -8,6 +8,7 @@ input_api = static_library( 'ThreadInputStream.cxx', 'AsyncInputStream.cxx', 'ProxyInputStream.cxx', + 'LastInputStream.cxx', include_directories: inc, dependencies: [ boost_dep,