From 40c6e80c2c9c96aa076316f127b2d42ab4cb1410 Mon Sep 17 00:00:00 2001 From: epoupon Date: Thu, 24 Sep 2015 13:12:09 +0200 Subject: [PATCH] [LMSAPI] Removed unused LMS API --- README.md | 4 +- configure.ac | 35 +- lms-api/proto/auth.proto | 65 -- lms-api/proto/collection.proto | 195 ---- lms-api/proto/media.proto | 137 --- lms-api/proto/messages.proto | 69 -- src/Makefile.am | 48 +- src/config/ConfigReader.cpp | 98 -- src/config/ConfigReader.hpp | 50 - src/cover/CoverArtGrabber.cpp | 1 - src/lms-api/messages/Header.hpp | 105 -- .../server/AudioCollectionRequestHandler.cpp | 393 ------- .../server/AudioCollectionRequestHandler.hpp | 61 -- src/lms-api/server/AuthRequestHandler.cpp | 105 -- src/lms-api/server/AuthRequestHandler.hpp | 47 - src/lms-api/server/Connection.cpp | 250 ----- src/lms-api/server/Connection.hpp | 98 -- src/lms-api/server/ConnectionManager.cpp | 62 -- src/lms-api/server/ConnectionManager.hpp | 58 -- src/lms-api/server/MediaRequestHandler.cpp | 217 ---- src/lms-api/server/MediaRequestHandler.hpp | 65 -- src/lms-api/server/RequestHandler.cpp | 101 -- src/lms-api/server/RequestHandler.hpp | 58 -- src/lms-api/server/Server.cpp | 112 -- src/lms-api/server/Server.hpp | 82 -- src/service/DatabaseUpdateService.cpp | 2 - test/CheckDbBasics.cpp | 2 +- test/Makefile.am | 29 - test/RemoteClient.cpp | 986 ------------------ 29 files changed, 7 insertions(+), 3528 deletions(-) delete mode 100644 lms-api/proto/auth.proto delete mode 100644 lms-api/proto/collection.proto delete mode 100644 lms-api/proto/media.proto delete mode 100644 lms-api/proto/messages.proto delete mode 100644 src/config/ConfigReader.cpp delete mode 100644 src/config/ConfigReader.hpp delete mode 100644 src/lms-api/messages/Header.hpp delete mode 100644 src/lms-api/server/AudioCollectionRequestHandler.cpp delete mode 100644 src/lms-api/server/AudioCollectionRequestHandler.hpp delete mode 100644 src/lms-api/server/AuthRequestHandler.cpp delete mode 100644 src/lms-api/server/AuthRequestHandler.hpp delete mode 100644 src/lms-api/server/Connection.cpp delete mode 100644 src/lms-api/server/Connection.hpp delete mode 100644 src/lms-api/server/ConnectionManager.cpp delete mode 100644 src/lms-api/server/ConnectionManager.hpp delete mode 100644 src/lms-api/server/MediaRequestHandler.cpp delete mode 100644 src/lms-api/server/MediaRequestHandler.hpp delete mode 100644 src/lms-api/server/RequestHandler.cpp delete mode 100644 src/lms-api/server/RequestHandler.hpp delete mode 100644 src/lms-api/server/Server.cpp delete mode 100644 src/lms-api/server/Server.hpp delete mode 100644 test/RemoteClient.cpp diff --git a/README.md b/README.md index 6c029ea3..2ecaa872 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,9 @@ This command requires root privileges ```sh $ /usr/bin/lms --docroot='/usr/share/lms/docroot/;/resources,/css,/images' --approot=/usr/share/lms/approot --http-address 0.0.0.0 --http-port 5081 ``` -The exectuable needs write accesses to the /var/lms/ directory +It is highly recommended to run LMS as a non root user. +The exectuable needs write accesses to the /var/lms/ directory. + ## Setting up SSL materials (optional) Here is just a self signed certificate example, you could do use a CA if you want. diff --git a/configure.ac b/configure.ac index f7e9611a..c7af1f14 100644 --- a/configure.ac +++ b/configure.ac @@ -8,41 +8,10 @@ AC_LANG_CPLUSPLUS # Checks for programs AC_PROG_CXX - -AC_ARG_ENABLE(lmsapi, AS_HELP_STRING([--enable-lmsapi], - [Build with the lmsapi protocol support. Defaults to yes.])], - [enable_lmsapi="$enableval"], - [enable_lmsapi="yes"]) - -# ProtoBuf compiler. -# First, specify with --with-protoc=/path/of/protoc. -# Or, specify with env variable PROTOC. -# If neither of the above, find it in the path. -AS_IF([test "$enable_lmsapi" = "yes"], - [AC_ARG_WITH([protoc], - [AS_HELP_STRING([--with-protoc=/path/of/protoc], - [Location of the protocol buffers compiler protoc. Defaults to looking on path.])], - [PROTOC="$withval"], - [ AS_IF([test "x${PROTOC}" == "x"], - [AC_PATH_PROG([PROTOC], [protoc], [no])])] - ) - ] - [ AS_IF([test "${PROTOC}" == "no"], [AC_MSG_ERROR([ProtoBuf compiler "protoc" not found.])]) ] - [AC_CHECK_LIB( [protobuf], - [main], - , - [AC_MSG_ERROR([libprotobuf not found!])])] - [lmsapi=true] - , - [lmsapi=false]) - -AM_CONDITIONAL([LMSAPI], [test x$lmsapi = xtrue]) -AS_IF([test x$lmsapi = xtrue], [AC_DEFINE(HAVE_LMSAPI, [1], [Enable LMS API support])]) - AC_ARG_ENABLE([video], AS_HELP_STRING([--enable-video], - [Enable Video support. Default to yes.])], + [Enable Video support. Default to no.])], [enable_video="$enableval"], - [enable_video="yes"]) + [enable_video="no"]) AM_CONDITIONAL([VIDEO], [test x$enable_video = xyes]) AS_IF([test x$enable_video = xyes], [AC_DEFINE(HAVE_VIDEO, [1], [Enable Video support])]) diff --git a/lms-api/proto/auth.proto b/lms-api/proto/auth.proto deleted file mode 100644 index 1ad02a48..00000000 --- a/lms-api/proto/auth.proto +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -package LmsAPI; - -message AuthRequest -{ - message Password - { - required string user_login = 1; - required string user_password = 2; - } - - enum Type - { - TypePassword = 1; - } - - required Type type = 1; - - optional Password password = 2; -} - -message AuthResponse -{ - - message PasswordResult - { - enum Type - { - TypePasswordInvalid = 1; - TypeLoginThrottling = 2; // The attempt was not processed because of throttling - TypePasswordValid = 3; - } - required Type type = 1; - - optional uint32 delay = 2; // in seconds, in case of PasswordInvalid/LoginThrottling - } - - enum Type - { - TypePasswordResult = 1; - } - - required Type type = 1; - - optional PasswordResult password_result = 2; -} - diff --git a/lms-api/proto/collection.proto b/lms-api/proto/collection.proto deleted file mode 100644 index 8666a98b..00000000 --- a/lms-api/proto/collection.proto +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -package LmsAPI; - -message AudioCollectionRequest -{ - - message SearchFilter - { - repeated uint64 artist_id = 1; // has one of these artists - repeated uint64 genre_id = 2; // has one of these genres - repeated uint64 release_id = 3; // hase one of these releases - repeated uint64 track_id = 4; // has one of theses tracks - } - - message BatchParameter - { - required uint32 offset = 1; // First element requested - required uint32 size = 2; // Number of elements requested. Server may not honor this size if too big - } - - message GetGenreList - { - required BatchParameter batch_parameter = 1; - optional SearchFilter search_filter = 2; - } - - message GetArtistList - { - required BatchParameter batch_parameter = 1; - optional SearchFilter search_filter = 2; - } - - message GetReleaseList - { - required BatchParameter batch_parameter = 1; - optional SearchFilter search_filter = 2; - } - - message GetTrackList - { - required BatchParameter batch_parameter = 1; - optional SearchFilter search_filter = 2; - } - - message GetCoverArt - { - enum Type - { - TypeGetCoverArtRelease = 1; - TypeGetCoverArtTrack = 2; - } - - required Type type = 1; - - optional uint64 release_id = 2; // Release that owns the cover art - optional uint64 track_id = 3; // Track that owns the cover art - - required uint32 size = 4; // Scale image to size*size pixels. Set 0 to get the biggest image - } - - enum Type - { - TypeGetRevision = 1; - TypeGetGenreList = 2; - TypeGetArtistList = 3; - TypeGetReleaseList = 4; - TypeGetTrackList = 5; - TypeGetCoverArt = 6; - } - - required Type type = 1; - - optional GetGenreList get_genres = 3; - optional GetArtistList get_artists = 4; - optional GetReleaseList get_releases = 5; - optional GetTrackList get_tracks = 6; - optional GetCoverArt get_cover_art = 7; -} - - -message AudioCollectionResponse -{ - - message Revision - { - required string rev = 1; // Unique identifier of the database revision - } - - message GenreList - { - repeated Genre genres = 1; - } - - message ArtistList - { - repeated Artist artists = 1; - } - - message ReleaseList - { - repeated Release releases = 1; - } - - message TrackList - { - repeated Track tracks = 1; - } - - message CoverArt - { - optional string mime_type = 1; - required bytes data = 2; - } - - message Genre - { - required uint64 id = 1; - optional string mbid = 2; - required string name = 3; - } - - message Artist - { - required uint64 id = 1; - optional string mbid = 2; - required string name = 3; - } - - message Release - { - required uint64 id = 1; - optional string mbid = 2; - required string name = 3; - } - - message Track - { - required uint64 id = 1; // Track id - optional string mbid = 2; - - required uint64 artist_id = 3; - required uint64 release_id = 4; - repeated uint64 genre_id = 5; - - optional string artist_mbid = 6; - optional string release_mbid = 7; - optional uint32 disc_number = 8; - optional uint32 track_number = 9; - required string name = 10; - required uint32 duration_secs = 11; - optional string release_date = 12; - optional string original_release_date = 13; - } - - enum Type { - TypeRevision = 1; - TypeGenreList = 2; - TypeArtistList = 3; - TypeReleaseList = 4; - TypeTrackList = 5; - TypeCoverArt = 6; - } - - - required Type type = 1; - - optional Revision revision = 2; - optional GenreList genre_list = 3; - optional ArtistList artist_list = 4; - optional ReleaseList release_list = 5; - optional TrackList track_list = 6; - repeated CoverArt cover_art = 7; -} - - - - diff --git a/lms-api/proto/media.proto b/lms-api/proto/media.proto deleted file mode 100644 index 20af5d02..00000000 --- a/lms-api/proto/media.proto +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -package LmsAPI; - -message MediaRequest -{ - - message Prepare - { - - enum AudioCodecType - { - AudioCodecTypeOGA = 1; - } - enum AudioBitrate { - AudioBitrate_32_kbps = 1; - AudioBitrate_64_kbps = 2; - AudioBitrate_96_kbps = 3; - AudioBitrate_128_kbps = 4; - AudioBitrate_192_kbps = 5; - AudioBitrate_256_kbps = 6; - } - - enum VideoCodecType - { - VideoCodecTypeOGV = 1; - } - enum VideoBitrate { - VideoBitrate_512_kbps = 1; - } - - message Audio - { - required int64 track_id = 1; // Id if the media - required AudioCodecType codec_type = 2; - required AudioBitrate bitrate = 3; - optional uint32 stream_idx = 4; - optional uint32 offset_secs = 5; - } - - message Video - { - required int64 video_id = 1; // Id if the media - required VideoCodecType codec_type = 2; - required AudioBitrate audio_bitrate = 3; - required VideoBitrate video_bitrate = 4; - optional uint32 offset_secs = 5; - optional uint32 audio_stream_idx = 6; - optional uint32 video_stream_idx = 7; - optional uint32 subtitle_stream_idx = 8; - } - - enum Type { - AudioRequest = 1; - VideoRequest = 2; - } - - required Type type = 1; - - optional Audio audio = 2; - optional Video video = 3; - } - - message GetPart - { - required uint32 handle = 1; // handle that uniquely identify the media. Get using the Prepare request - required uint32 requested_data_size = 2; // Amount of data requested. May receive more or less. May receive 0 byte if complete - } - - message Terminate - { - required uint32 handle = 1; - } - - enum Type - { - TypeMediaPrepare = 1; - TypeMediaGetPart = 2; - TypeMediaTerminate = 3; - } - - required Type type = 1; - - optional Prepare prepare = 2; - optional GetPart get_part = 3; - optional Terminate terminate = 4; - -} // MediaRequest - -message MediaResponse -{ - - message PrepareResult - { - optional uint32 handle = 1; // handle iif prepare request was ok - } - - message PartResult - { - optional bytes data = 2; // 0 bytes when the media is over, nothing when the request is ill formed - } - - message TerminateResult - { - } - - enum Type - { - TypePrepareResult = 1; - TypePartResult = 2; - TypeTerminateResult = 3; - } - - required Type type = 1; - - optional PrepareResult prepare_result = 2; - optional PartResult part_result = 3; - optional TerminateResult terminate_result = 4; -} - diff --git a/lms-api/proto/messages.proto b/lms-api/proto/messages.proto deleted file mode 100644 index a6eb280b..00000000 --- a/lms-api/proto/messages.proto +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -import "auth.proto"; -import "collection.proto"; -import "media.proto"; - -package LmsAPI; - -// Every request sent by the client must be a ClientMessage -// The server will answer using a ServerMessage -// -// The client must authenticate first before querying data -// If an expected message is received, the connection is dropped by the server -// -// A header is to be added before the serialized protobuf message in order to keep -// track of where one message ends and the next begins. -// Format: -// MAGIC (4 bytes, 0xDE, 0xAD, 0xBE, 0xEF)- SIZE (4 bytes, big endian encoded) - serialized proto message -message ClientMessage -{ - enum Type - { - AuthRequest = 1; - AudioCollectionRequest = 2; - MediaRequest = 3; - } - - required Type type = 1; - - optional AuthRequest auth_request = 2; - optional AudioCollectionRequest audio_collection_request = 3; - optional MediaRequest media_request = 4; -} - - -message ServerMessage -{ - enum Type - { - AuthResponse = 1; - AudioCollectionResponse = 2; - MediaResponse = 3; - } - - required Type type = 1; - - optional AuthResponse auth_response = 2; - optional AudioCollectionResponse audio_collection_response = 3; - optional MediaResponse media_response = 4; -} - - diff --git a/src/Makefile.am b/src/Makefile.am index 33a25015..ce6a0c12 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,52 +59,6 @@ lms_SOURCES += \ $(srcdir)/ui/video/VideoParametersDialog.cpp endif -if LMSAPI -lms_SOURCES += \ - $(srcdir)/lms-api/server/Connection.cpp \ - $(srcdir)/lms-api/server/ConnectionManager.cpp \ - $(srcdir)/lms-api/server/AudioCollectionRequestHandler.cpp \ - $(srcdir)/lms-api/server/AuthRequestHandler.cpp \ - $(srcdir)/lms-api/server/MediaRequestHandler.cpp \ - $(srcdir)/lms-api/server/RequestHandler.cpp \ - $(srcdir)/lms-api/server/Server.cpp \ - $(srcdir)/service/LmsAPIServerService.cpp - -nodist_lms_SOURCES = \ - $(builddir)/auth.pb.cc \ - $(builddir)/auth.pb.h \ - $(builddir)/collection.pb.cc \ - $(builddir)/collection.pb.h \ - $(builddir)/media.pb.cc \ - $(builddir)/media.pb.h \ - $(builddir)/messages.pb.cc \ - $(builddir)/messages.pb.h - -BUILT_SOURCES = \ - $(builddir)/auth.pb.cc \ - $(builddir)/auth.pb.h \ - $(builddir)/collection.pb.cc \ - $(builddir)/collection.pb.h \ - $(builddir)/media.pb.cc \ - $(builddir)/media.pb.h \ - $(builddir)/messages.pb.cc \ - $(builddir)/messages.pb.h - -MOSTLYCLEANFILES = \ - $(builddir)/auth.pb.cc \ - $(builddir)/auth.pb.h \ - $(builddir)/collection.pb.cc \ - $(builddir)/collection.pb.h \ - $(builddir)/media.pb.cc \ - $(builddir)/media.pb.h \ - $(builddir)/messages.pb.cc \ - $(builddir)/messages.pb.h - -%.pb.cc %.pb.h: $(top_srcdir)/lms-api/proto/%.proto - $(PROTOC) --proto_path=$(top_srcdir)/lms-api/proto/ --cpp_out=$(builddir)/ $^ - -endif - -lms_CXXFLAGS=-std=c++11 -Wall -I$(top_srcdir)/third-party -I$(srcdir)/ui -I$(srcdir)/lms-api $(MAGICKXX_CFLAGS) +lms_CXXFLAGS=-std=c++11 -Wall -I$(top_srcdir)/third-party -I$(srcdir)/ui $(MAGICKXX_CFLAGS) lms_LDADD=$(MAGICKXX_LIBS) diff --git a/src/config/ConfigReader.cpp b/src/config/ConfigReader.cpp deleted file mode 100644 index 1598e71b..00000000 --- a/src/config/ConfigReader.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include - -#include "ConfigReader.hpp" - -namespace { - -} - -ConfigReader::ConfigReader() -: _config (nullptr) -{ -} - -ConfigReader& -ConfigReader::instance() -{ - static ConfigReader instance; - return instance; -} - -void -ConfigReader::setFile(boost::filesystem::path p) -{ - if (_config != nullptr) - delete _config; - - _config = new libconfig::Config(); - - _config->readFile(p.string().c_str()); -} - -std::string -ConfigReader::getString(std::string setting, std::string def) -{ - try { - return _config->lookup(setting); - } - catch (std::exception &e) - { - return def; - } -} - -unsigned long -ConfigReader::getULong(std::string setting, unsigned long def) -{ - try { - return static_cast(_config->lookup(setting)); - } - catch (...) - { - return def; - } -} - -long -ConfigReader::getLong(std::string setting, long def) -{ - try { - return _config->lookup(setting); - } - catch (...) - { - return def; - } -} - -bool -ConfigReader::getBool(std::string setting, bool def) -{ - try { - return _config->lookup(setting); - } - catch (...) - { - return def; - } -} - diff --git a/src/config/ConfigReader.hpp b/src/config/ConfigReader.hpp deleted file mode 100644 index c503053a..00000000 --- a/src/config/ConfigReader.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef CONFIG_READER_HPP -#define CONFIG_READER_HPP - -#include -#include - -class ConfigReader -{ - public: - - ConfigReader(const ConfigReader&) = delete; - ConfigReader& operator=(const ConfigReader&) = delete; - - static ConfigReader& instance(); - - void setFile(boost::filesystem::path p); - - /* Default values are returned in case of setting not found */ - std::string getString(std::string setting, std::string def = ""); - unsigned long getULong(std::string setting, unsigned long def = 0); - long getLong(std::string setting, long def = 0); - bool getBool(std::string setting, bool def = false); - - private: - - ConfigReader(); - - libconfig::Config *_config; -}; - -#endif diff --git a/src/cover/CoverArtGrabber.cpp b/src/cover/CoverArtGrabber.cpp index 4b791049..738d04f3 100644 --- a/src/cover/CoverArtGrabber.cpp +++ b/src/cover/CoverArtGrabber.cpp @@ -18,7 +18,6 @@ */ #include "logger/Logger.hpp" -#include "config/ConfigReader.hpp" #include "av/AvInfo.hpp" #include "CoverArtGrabber.hpp" diff --git a/src/lms-api/messages/Header.hpp b/src/lms-api/messages/Header.hpp deleted file mode 100644 index d0e97cc6..00000000 --- a/src/lms-api/messages/Header.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_HEADER_HPP -#define REMOTE_HEADER_HPP - -#include - -namespace LmsAPI -{ - - -class Header -{ - public: - static const std::size_t size = 8; // HeaderSize - static const std::size_t max_data_size = 65536*64 - size; - - Header() : _dataSize(0) {} - - void setDataSize(std::size_t size) { _dataSize = size; } - std::size_t getDataSize(void) const {return _dataSize;} - - bool from_istream(std::istream &is) - { - std::array buffer; - - bool res = is.read(reinterpret_cast(buffer.data()), buffer.size()); - - if (res && is.gcount() == buffer.size()) - return from_buffer(buffer); - else - return false; - } - - bool from_buffer(const std::array& buffer) - { - if (decode32(&buffer[0]) != _magic) - { - return false; - } - else - { - _dataSize = decode32(&buffer[4]); - return _dataSize <= max_data_size; - } - } - -/* void to_ostream(std::ostream& os) - { - - - }*/ - - void to_buffer(std::array& buffer) const - { - encode32(_magic, &buffer[0]); - encode32(_dataSize, &buffer[4]); - } - - private: - static uint32_t decode32(const unsigned char* data) - { - return (static_cast(data[0]) << 24) - + (static_cast(data[1]) << 16) - + (static_cast(data[2]) << 8) - + (static_cast(data[3])); - } - - static void encode32(uint32_t value, unsigned char* data) - { - data[0] = (value >> 24) & 0xFF; - data[1] = (value >> 16) & 0xFF; - data[2] = (value >> 8) & 0xFF; - data[3] = (value) & 0xFF; - } - - static const uint32_t _magic = 0xdeadbeef; - - uint32_t _dataSize; -}; - - - -} // namespace LmsAPI - - -#endif - diff --git a/src/lms-api/server/AudioCollectionRequestHandler.cpp b/src/lms-api/server/AudioCollectionRequestHandler.cpp deleted file mode 100644 index 2f4a5427..00000000 --- a/src/lms-api/server/AudioCollectionRequestHandler.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include // std::min - -#include -#include - -#include "logger/Logger.hpp" - -#include "AudioCollectionRequestHandler.hpp" - -#include "database/Types.hpp" -#include "cover/CoverArtGrabber.hpp" - -namespace LmsAPI { -namespace Server { - -using namespace Database; - -static SearchFilter SearchFilterFromRequest(const AudioCollectionRequest_SearchFilter& request) -{ - SearchFilter filter; - - for (int id = 0; id < request.artist_id_size(); ++id) - filter.idMatch[SearchFilter::Field::Artist].push_back( request.artist_id(id) ); - - for (int id = 0; id < request.genre_id_size(); ++id) - filter.idMatch[SearchFilter::Field::Genre].push_back( request.genre_id(id) ); - - for (int id = 0; id < request.release_id_size(); ++id) - filter.idMatch[SearchFilter::Field::Release].push_back( request.release_id(id) ); - - for (int id = 0; id < request.track_id_size(); ++id) - filter.idMatch[SearchFilter::Field::Track].push_back( request.track_id(id) ); - - return filter; -} - -AudioCollectionRequestHandler::AudioCollectionRequestHandler(Handler& db) -: _db(db) -{} - -bool -AudioCollectionRequestHandler::process(const AudioCollectionRequest& request, AudioCollectionResponse& response) -{ - - bool res = false; - - switch (request.type()) - { - case AudioCollectionRequest::TypeGetRevision: - // No payload - res = processGetRevision(*response.mutable_revision()); - if (res) - response.set_type(AudioCollectionResponse::TypeRevision); - break; - - case AudioCollectionRequest::TypeGetGenreList: - if (request.has_get_genres()) - { - res = processGetGenres(request.get_genres(), *response.mutable_genre_list()); - if (res) - response.set_type(AudioCollectionResponse::TypeArtistList); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AudioCollectionRequest::TypeGetGenreList"; - break; - - case AudioCollectionRequest::TypeGetArtistList: - if (request.has_get_artists()) - { - res = processGetArtists(request.get_artists(), *response.mutable_artist_list()); - if (res) - response.set_type(AudioCollectionResponse::TypeArtistList); - - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AudioCollectionRequest::TypeGetArtistList message!"; - break; - - case AudioCollectionRequest::TypeGetReleaseList: - if (request.has_get_releases()) - { - res = processGetReleases(request.get_releases(), *response.mutable_release_list()); - if (res) - response.set_type(AudioCollectionResponse::TypeReleaseList); - - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AudioCollectionRequest::TypeGetReleaseList message!"; - break; - - case AudioCollectionRequest::TypeGetTrackList: - if (request.has_get_tracks()) - { - res = processGetTracks(request.get_tracks(), *response.mutable_track_list()); - if (res) - response.set_type(AudioCollectionResponse::TypeTrackList); - - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AudioCollectionRequest::TypeGetTrackList message!"; - break; - - case AudioCollectionRequest::TypeGetCoverArt: - if (request.has_get_cover_art()) - res = processGetCoverArt(request.get_cover_art(), response); - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AudioCollectionRequest::TypeGetCoverArt message!"; - break; - - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Unhandled AudioCollectionRequest_Type = " << request.type(); - - } - - return res; -} - - -bool -AudioCollectionRequestHandler::processGetGenres(const AudioCollectionRequest::GetGenreList& request, AudioCollectionResponse::GenreList& response) -{ - // sanity checks - if (!request.has_batch_parameter()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No batch parameters found!"; - return false; - } - - std::size_t size = request.batch_parameter().size(); - if (!size) - size = _maxListArtists; - size = std::min(size, _maxListArtists); - - // Get filters - SearchFilter filter; - if (request.has_search_filter()) - filter = SearchFilterFromRequest(request.search_filter()); - - Wt::Dbo::Transaction transaction( _db.getSession() ); - - std::vector genres = Genre::getByFilter( _db.getSession(), filter, request.batch_parameter().offset(), static_cast(size)); - - for (Genre::pointer genre : genres) - { - AudioCollectionResponse_Genre* addGenre = response.add_genres(); - - addGenre->set_id(genre.id()); - addGenre->set_name( std::string( boost::locale::conv::to_utf(genre->getName(), "UTF-8") ) ); - } - - return true; -} - -bool -AudioCollectionRequestHandler::processGetArtists(const AudioCollectionRequest::GetArtistList& request, AudioCollectionResponse::ArtistList& response) -{ - // sanity checks - if (!request.has_batch_parameter()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No batch parameters found!"; - return false; - } - - std::size_t size = request.batch_parameter().size(); - if (!size) - size = _maxListArtists; - size = std::min(size, _maxListArtists); - - // Get filters - SearchFilter filter; - if (request.has_search_filter()) - filter = SearchFilterFromRequest(request.search_filter()); - - // Now fetch requested data... - - Wt::Dbo::Transaction transaction( _db.getSession() ); - - std::vector artists - = Artist::getByFilter(_db.getSession(), filter, - request.batch_parameter().offset(), static_cast(size) ); - - for (Artist::pointer artist : artists) - { - AudioCollectionResponse_Artist *addArtist = response.add_artists(); - - addArtist->set_id(artist.id()); - addArtist->set_name( std::string( boost::locale::conv::to_utf(artist->getName(), "UTF-8") ) ); - if (!artist->getMBID().empty()) - addArtist->set_mbid(artist->getMBID()); - } - - return true; -} - -bool -AudioCollectionRequestHandler::processGetReleases(const AudioCollectionRequest::GetReleaseList& request, AudioCollectionResponse::ReleaseList& response) -{ - // sanity checks - if (!request.has_batch_parameter()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No batch parameters found!"; - return false; - } - - std::size_t size = request.batch_parameter().size(); - if (!size) - size = _maxListReleases; - size = std::min(size, _maxListReleases); - - // Get filters - SearchFilter filter; - if (request.has_search_filter()) - filter = SearchFilterFromRequest(request.search_filter()); - - Wt::Dbo::Transaction transaction( _db.getSession() ); - - std::vector releases - = Release::getByFilter( _db.getSession(), filter, - request.batch_parameter().offset(), static_cast(size)); - - for (Release::pointer release : releases) - { - AudioCollectionResponse_Release *addRelease = response.add_releases(); - - addRelease->set_id(release.id()); - addRelease->set_name( std::string( boost::locale::conv::to_utf(release->getName(), "UTF-8"))); - if (!release->getMBID().empty()) - addRelease->set_mbid(release->getMBID()); - } - - return true; -} - -bool -AudioCollectionRequestHandler::processGetTracks(const AudioCollectionRequest::GetTrackList& request, AudioCollectionResponse::TrackList& response) -{ - // sanity checks - if (!request.has_batch_parameter()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No batch parameters found!"; - return false; - } - - std::size_t size = request.batch_parameter().size(); - if (!size) - size = _maxListTracks; - size = std::min(size, _maxListTracks); - - // Get filters - SearchFilter filter; - if (request.has_search_filter()) - filter = SearchFilterFromRequest(request.search_filter()); - - Wt::Dbo::Transaction transaction( _db.getSession() ); - - std::vector tracks - = Track::getByFilter( _db.getSession(), filter, - request.batch_parameter().offset(), static_cast(size)); - - for (Track::pointer track : tracks) - { - AudioCollectionResponse_Track* newTrack = response.add_tracks(); - - newTrack->set_id(track.id()); - newTrack->set_disc_number( track->getDiscNumber() ); - newTrack->set_track_number( track->getTrackNumber() ); - newTrack->set_artist_id( track->getArtist().id() ); - newTrack->set_release_id( track->getRelease().id() ); - - newTrack->set_name( std::string( boost::locale::conv::to_utf(track->getName(), "UTF-8") ) ); - newTrack->set_duration_secs( track->getDuration().total_seconds() ); - - // Only send the year part of the release times - if (!track->getDate().is_special()) - newTrack->set_release_date( std::to_string(track->getDate().date().year()) ); - if (!track->getOriginalDate().is_special()) - newTrack->set_original_release_date( std::to_string(track->getOriginalDate().date().year()) ); - if (!track->getMBID().empty()) - newTrack->set_mbid(track->getMBID()); - - for (Genre::pointer genre : track->getGenres()) - newTrack->add_genre_id( genre.id() ); - - } - - return true; -} - -bool -AudioCollectionRequestHandler::processGetCoverArt(const AudioCollectionRequest::GetCoverArt& request, AudioCollectionResponse& response) -{ - bool res = false; - - response.set_type(AudioCollectionResponse::TypeCoverArt); - - std::vector coverArts; - - switch(request.type()) - { - case AudioCollectionRequest::GetCoverArt::TypeGetCoverArtRelease: - if (request.has_release_id()) - { - coverArts = CoverArt::Grabber::instance().getFromRelease( _db.getSession(), request.release_id()); - res = true; - } - break; - - case AudioCollectionRequest::GetCoverArt::TypeGetCoverArtTrack: - if (request.has_track_id()) - { - coverArts = CoverArt::Grabber::instance().getFromTrack(_db.getSession(), request.track_id()); - res = true; - } - break; - } - - for (CoverArt::CoverArt& coverArt : coverArts) - { - AudioCollectionResponse_CoverArt* cover_art = response.add_cover_art(); - - if (request.has_size()) - { - std::size_t size = request.size(); - if (size > _maxCoverArtSize || size == 0) - size = _maxCoverArtSize; - if (size < _minCoverArtSize) - size = _minCoverArtSize; - - coverArt.scale(size); - } - - cover_art->set_mime_type(coverArt.getMimeType()); - cover_art->set_data( std::string( coverArt.getData().begin(), coverArt.getData().end()) ); - } - - return res; -} - -bool -AudioCollectionRequestHandler::processGetRevision(AudioCollectionResponse::Revision& response) -{ - - bool res = false; - - Wt::Dbo::Transaction transaction( _db.getSession() ); - - MediaDirectorySettings::pointer settings = MediaDirectorySettings::get( _db.getSession() ); - - std::string hashStr = boost::posix_time::to_iso_string(settings->getLastUpdated()); - - boost::uuids::detail::sha1 s; - for (const char c : hashStr) - s.process_byte(c); - - unsigned int digest[5]; - s.get_digest(digest); - - std::ostringstream oss; - for (std::size_t i = 0; i < 5; ++i) - oss << std::hex << std::setfill('0') << std::setw(4) << digest[i]; - - response.set_rev(oss.str()); - - res = true; - - return res; -} - - - -} // namespace LmsAPI -} // namespace Server - - diff --git a/src/lms-api/server/AudioCollectionRequestHandler.hpp b/src/lms-api/server/AudioCollectionRequestHandler.hpp deleted file mode 100644 index 5d7522c4..00000000 --- a/src/lms-api/server/AudioCollectionRequestHandler.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_AUDIO_COLLECTION_REQUEST_HANDLER -#define REMOTE_AUDIO_COLLECTION_REQUEST_HANDLER - -#include "database/DatabaseHandler.hpp" - -#include "messages.pb.h" - -namespace LmsAPI { -namespace Server { - -class AudioCollectionRequestHandler -{ - public: - AudioCollectionRequestHandler(Database::Handler& db); - - bool process(const AudioCollectionRequest& request, AudioCollectionResponse& response); - - private: - - bool processGetRevision(AudioCollectionResponse::Revision& response); - bool processGetArtists(const AudioCollectionRequest::GetArtistList& request, AudioCollectionResponse::ArtistList& response); - bool processGetGenres(const AudioCollectionRequest::GetGenreList& request, AudioCollectionResponse::GenreList& response); - bool processGetReleases(const AudioCollectionRequest::GetReleaseList& request, AudioCollectionResponse::ReleaseList& response); - bool processGetTracks(const AudioCollectionRequest::GetTrackList& request, AudioCollectionResponse::TrackList& response); - bool processGetCoverArt(const AudioCollectionRequest::GetCoverArt& request, AudioCollectionResponse& response); - - Database::Handler& _db; - - static const std::size_t _maxListArtists = 256; - static const std::size_t _maxListGenres = 256; - static const std::size_t _maxListReleases = 128; - static const std::size_t _maxListTracks = 128; - - static const std::size_t _minCoverArtSize = 64; // in pixels, square - static const std::size_t _maxCoverArtSize = 512; // in pixels, square -}; - -} // namespace LmsAPI -} // namespace Server - -#endif - diff --git a/src/lms-api/server/AuthRequestHandler.cpp b/src/lms-api/server/AuthRequestHandler.cpp deleted file mode 100644 index b0f98a70..00000000 --- a/src/lms-api/server/AuthRequestHandler.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include - -#include "logger/Logger.hpp" - -#include "AuthRequestHandler.hpp" - -namespace LmsAPI { -namespace Server { - -AuthRequestHandler::AuthRequestHandler(Database::Handler& db) -: _db(db) -{ -} - -bool -AuthRequestHandler::process(const AuthRequest& request, AuthResponse& response) -{ - bool res = false; - - switch (request.type()) - { - case AuthRequest::TypePassword: - if (request.has_password()) - { - res = processPassword(request.password(), *response.mutable_password_result()); - if (res) - response.set_type(AuthResponse::TypePasswordResult); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad AuthRequest::TypePassword"; - break; - } - - return res; -} - - -bool -AuthRequestHandler::processPassword(const AuthRequest::Password& request, AuthResponse::PasswordResult& response) -{ - bool res = false; - - // Get the user - const Wt::Auth::User& user = _db.getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, request.user_login()); - if (user.isValid()) - { - // Now attempt to log the user in - - Wt::Auth::PasswordResult result = _db.getPasswordService().verifyPassword(user, request.user_password()); - switch( result ) - { - case Wt::Auth::PasswordInvalid: - response.set_type(AuthResponse::PasswordResult::TypePasswordInvalid); - LMS_LOG(MOD_REMOTE, SEV_NOTICE) << "User '" << request.user_login() << "': invalid password"; - res = true; - break; - case Wt::Auth::LoginThrottling: - response.set_type(AuthResponse::PasswordResult::TypeLoginThrottling); - response.set_delay(_db.getPasswordService().delayForNextAttempt(user)); - res = true; - break; - case Wt::Auth::PasswordValid: - response.set_type(AuthResponse::PasswordResult::TypePasswordValid); - // Log the user in - _db.getLogin().login( user ); - LMS_LOG(MOD_REMOTE, SEV_NOTICE) << "User '" << request.user_login() << "' successfully logged in"; - res = true; - break; - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Cannot handle password result!"; - break; - } - - } - else - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Invalid user '" << request.user_login(); - response.set_type(AuthResponse::PasswordResult::TypePasswordInvalid); - } - - return res; -} - -} // namespace Server -} // namespace LmsAPI - diff --git a/src/lms-api/server/AuthRequestHandler.hpp b/src/lms-api/server/AuthRequestHandler.hpp deleted file mode 100644 index 363dcab2..00000000 --- a/src/lms-api/server/AuthRequestHandler.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef LMSAPI_AUTH_REQUEST_HANDLER -#define LMSAPI_AUTH_REQUEST_HANDLER - -#include "database/DatabaseHandler.hpp" - -#include "messages.pb.h" - -namespace LmsAPI { -namespace Server { - -class AuthRequestHandler -{ - public: - AuthRequestHandler(Database::Handler& db); - - bool process(const AuthRequest& request, AuthResponse& response); - - private: - - bool processPassword(const AuthRequest::Password& request, AuthResponse::PasswordResult& response); - - Database::Handler& _db; -}; - -} // namespace Server -} // namespace LmsAPI - -#endif diff --git a/src/lms-api/server/Connection.cpp b/src/lms-api/server/Connection.cpp deleted file mode 100644 index f8d0e688..00000000 --- a/src/lms-api/server/Connection.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - - -#include -#include - -#include -#include - -#include "logger/Logger.hpp" - -#include "messages.pb.h" - -#include "RequestHandler.hpp" - -#include "ConnectionManager.hpp" -#include "Connection.hpp" - -namespace LmsAPI { -namespace Server { - -Connection::Connection(boost::asio::io_service& ioService, - boost::asio::ssl::context& context, - ConnectionManager& manager, - Wt::Dbo::SqlConnectionPool& connectionPool) -: _closing(false), -_socket(ioService, context), -_connectionManager(manager), -_requestHandler(connectionPool) -{ - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Server::Connection::Connection, Creating connection"; -} - -void -Connection::start() -{ - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Starting connection..."; - _socket.async_handshake(boost::asio::ssl::stream_base::server, - boost::bind(&Connection::handleHandshake, this, - boost::asio::placeholders::error)); -} - -void -Connection::handleHandshake(const boost::system::error_code& error) -{ - if (!error) - { - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Handshake successfully performed... Now reading messages"; - readMsg(); - } - else if (error != boost::asio::error::operation_aborted) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Connection::handleHandshake: " << error.message(); - _connectionManager.stop(shared_from_this()); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Handshake error: " << error.message(); -} - - -void -Connection::readMsg() -{ - // Read a header first - boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(LmsAPI::Header::size); - - boost::asio::async_read(_socket, - bufs, - boost::asio::transfer_exactly(LmsAPI::Header::size), - boost::bind(&Connection::handleReadHeader, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); -} - -void -Connection::stop() -{ - if (!_closing) - { - boost::system::error_code ec; - - _closing = true; - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Server::Connection::stop, Stopping connection " << this; - _socket.shutdown(ec); - - if (ec) - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Error while shutting down connection " << this << ": " << ec.message(); - - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Server::Connection::stop, connection stopped " << this; - } - else - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Stop: close already in progress..."; -} - -void -Connection::handleReadHeader(const boost::system::error_code& error, std::size_t bytes_transferred) -{ - if (!error) - { - if (bytes_transferred != LmsAPI::Header::size) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "bytes_transferred (" << bytes_transferred << ") != LmsAPI::Header::size!"; - _connectionManager.stop(shared_from_this()); - return; - } - - _inputStreamBuf.commit(bytes_transferred); - - std::istream is(&_inputStreamBuf); - - LmsAPI::Header header; - if (!header.from_istream(is)) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Cannot read header from buffer!"; - _connectionManager.stop(shared_from_this()); - return; - } - - // Now read the real message payload - boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(header.getDataSize()); - - boost::asio::async_read(_socket, - bufs, - boost::asio::transfer_exactly(header.getDataSize()), - boost::bind(&Connection::handleReadMsg, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - - } - else if (error != boost::asio::error::operation_aborted) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Connection::handleReadHeader: " << error.message(); - _connectionManager.stop(shared_from_this()); - } -} - -void -Connection::handleReadMsg(const boost::system::error_code& error, std::size_t bytes_transferred) -{ - if (!error) - { - _inputStreamBuf.commit(bytes_transferred); - - std::istream is(&_inputStreamBuf); - std::ostream os(&_outputStreamBuf); - - LmsAPI::ServerMessage response; - LmsAPI::ClientMessage request; - - if (!request.ParseFromIstream(&is)) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Parse request failed!"; - _connectionManager.stop(shared_from_this()); - return; - } - - if (!_requestHandler.process(request, response)) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Process request failed!"; - _connectionManager.stop(shared_from_this()); - return; - } - - { - boost::system::error_code ec; - - if (!response.SerializeToOstream(&os)) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Cannot serialize to ostream!"; - _connectionManager.stop(shared_from_this()); - return; - } - - if (_outputStreamBuf.size() >= LmsAPI::Header::max_data_size) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "output message is too big! " << _outputStreamBuf.size() << " > " << LmsAPI::Header::max_data_size; - _connectionManager.stop(shared_from_this()); - return; - } - - std::array headerBuffer; - { - LmsAPI::Header header; - header.setDataSize(_outputStreamBuf.size()); - header.to_buffer(headerBuffer); - } - - std::size_t n = boost::asio::write(_socket, - boost::asio::buffer(headerBuffer), - boost::asio::transfer_exactly(LmsAPI::Header::size), - ec); - if (ec) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "cannot write header: " << error.message(); - _connectionManager.stop(shared_from_this()); - } - else - { - assert(n == LmsAPI::Header::size); - } - - // Now send serialized payload - n = boost::asio::write(_socket, - _outputStreamBuf.data(), - boost::asio::transfer_exactly(_outputStreamBuf.size()), - ec); - - if (ec) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "cannot write msg: " << error.message(); - _connectionManager.stop(shared_from_this()); - } - else - { - assert(n == _outputStreamBuf.size()); - _outputStreamBuf.consume(n); - } - - } - - // All good here, read another message - readMsg(); - } - else if (error != boost::asio::error::operation_aborted) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Connection::handleRead: " << error.message(); - _connectionManager.stop(shared_from_this()); - } -} - - -} // namespace Server -} // namespace LmsAPI diff --git a/src/lms-api/server/Connection.hpp b/src/lms-api/server/Connection.hpp deleted file mode 100644 index b254733f..00000000 --- a/src/lms-api/server/Connection.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef LMSAPI_CONNECTION_HPP -#define LMSAPI_CONNECTION_HPP - -#include -#include - -#include -#include - -#include "RequestHandler.hpp" - -#include "messages/Header.hpp" - -namespace LmsAPI { -namespace Server { - -class ConnectionManager; - -/// Represents a single connection from a client. -class Connection : public std::enable_shared_from_this -{ - public: - - typedef boost::asio::ssl::stream ssl_socket; - - Connection(const Connection&) = delete; - Connection& operator=(const Connection&) = delete; - - typedef std::shared_ptr pointer; - - /// Construct a connection with the given io_service. - explicit Connection(boost::asio::io_service& ioService, boost::asio::ssl::context& context, - ConnectionManager& manager, - Wt::Dbo::SqlConnectionPool& connectionPool); - - ssl_socket::lowest_layer_type& getSocket() {return _socket.lowest_layer();} - - /// Start the first asynchronous operation for the connection. - void start(); - - /// Stop all asynchronous operations associated with the connection. - void stop(); - - private: - bool _closing; - - /// Read a new message on the the connection - void readMsg(); - - /// Handle completion of ssl handshake - void handleHandshake(const boost::system::error_code& error); - - /// Handle completion of a read operation. - void handleReadHeader(const boost::system::error_code& e, - std::size_t bytes_transferred); - - void handleReadMsg(const boost::system::error_code& e, - std::size_t bytes_transferred); - - /// Socket for the connection. - ssl_socket _socket; - - /// The manager for this connection. - ConnectionManager& _connectionManager; - - /// The handler used to process the incoming requests. - RequestHandler _requestHandler; - - boost::asio::streambuf _inputStreamBuf; - boost::asio::streambuf _outputStreamBuf; -}; - - -} // namespace Server -} // namespace LmsAPI - -#endif - - diff --git a/src/lms-api/server/ConnectionManager.cpp b/src/lms-api/server/ConnectionManager.cpp deleted file mode 100644 index c4fc6eb7..00000000 --- a/src/lms-api/server/ConnectionManager.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include - -#include - -#include "ConnectionManager.hpp" - -namespace LmsAPI { -namespace Server { - -ConnectionManager::ConnectionManager() -{ -} - - -void -ConnectionManager::start(Connection::pointer c) -{ - _connections.insert(c); - c->start(); -} - -void -ConnectionManager::stop(Connection::pointer c) -{ - _connections.erase(c); - c->stop(); -} - -void -ConnectionManager::stopAll() -{ - BOOST_FOREACH(Connection::pointer c, _connections) - { - c->stop(); - } - _connections.clear(); -} - - -} // namespace Server -} // namespace LmsAPI - - diff --git a/src/lms-api/server/ConnectionManager.hpp b/src/lms-api/server/ConnectionManager.hpp deleted file mode 100644 index ce2b194a..00000000 --- a/src/lms-api/server/ConnectionManager.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_CONNECTION_MANAGER_HPP -#define REMOTE_CONNECTION_MANAGER_HPP - -#include - -#include "Connection.hpp" - -namespace LmsAPI { -namespace Server { - -/// Manages open connections so that they may be cleanly stopped when the server -/// needs to shut down. - -class ConnectionManager -{ - public: - ConnectionManager(const ConnectionManager&) = delete; - ConnectionManager& operator=(const ConnectionManager&) = delete; - - ConnectionManager(); - - /// Add the specified connection to the manager and start it. - void start(Connection::pointer c); - - /// Stop the specified connection. - void stop(Connection::pointer c); - - /// Stop all connections. - void stopAll(); - - private: - /// The managed connections. - std::set _connections; -}; - -} // namespace Server -} // namespace LmsAPI - -#endif diff --git a/src/lms-api/server/MediaRequestHandler.cpp b/src/lms-api/server/MediaRequestHandler.cpp deleted file mode 100644 index be3e6b53..00000000 --- a/src/lms-api/server/MediaRequestHandler.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include "logger/Logger.hpp" - -#include "MediaRequestHandler.hpp" - -#include "database/Types.hpp" - -namespace LmsAPI { -namespace Server { - -MediaRequestHandler::MediaRequestHandler(Database::Handler& db) -: _db(db) -{} - -bool -MediaRequestHandler::process(const MediaRequest& request, MediaResponse& response) -{ - - bool res = false; - - switch (request.type()) - { - case MediaRequest::TypeMediaPrepare: - if (request.has_prepare()) - { - if (request.prepare().has_audio()) - res = processAudioPrepare(request.prepare().audio(), *response.mutable_prepare_result()); - else if (request.prepare().has_video()) - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Video prepare not supported!"; - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad MediaRequest::TypeMediaPrepare!"; - - if (res) - response.set_type(MediaResponse::TypePrepareResult); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad MediaRequest::TypeMediaPrepare!"; - break; - - case MediaRequest::TypeMediaGetPart: - if (request.has_get_part()) - { - res = processGetPart(request.get_part(), *response.mutable_part_result()); - if (res) - response.set_type(MediaResponse::TypePartResult); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad MediaRequest::TypeMediaGet!"; - - break; - - case MediaRequest::TypeMediaTerminate: - if (request.has_terminate()) - { - res = processTerminate(request.terminate(), *response.mutable_terminate_result()); - if (res) - response.set_type(MediaResponse::TypePartResult); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad MediaRequest::TypeMediaTerminate!"; - - break; - - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Unhandled MediaRequest type = " << request.type(); - } - - return res; -} - -bool -MediaRequestHandler::processAudioPrepare(const MediaRequest::Prepare::Audio& request, MediaResponse::PrepareResult& response) -{ - std::size_t bitrate; - Transcode::Format::Encoding format; - - switch( request.codec_type()) - { - case MediaRequest::Prepare::AudioCodecTypeOGA: format = Transcode::Format::OGA; break; - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Unhandled codec type = " << request.codec_type(); - return false; - } - - switch( request.bitrate() ) - { - case MediaRequest::Prepare::AudioBitrate_32_kbps: bitrate = 32000; break; - case MediaRequest::Prepare::AudioBitrate_64_kbps: bitrate = 64000; break; - case MediaRequest::Prepare::AudioBitrate_96_kbps: bitrate = 96000; break; - case MediaRequest::Prepare::AudioBitrate_128_kbps: bitrate = 128000; break; - case MediaRequest::Prepare::AudioBitrate_192_kbps: bitrate = 192000; break; - case MediaRequest::Prepare::AudioBitrate_256_kbps: bitrate = 256000; break; - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Unhandled bitrate type = " << request.bitrate(); - return false; - } - - // TODO use user's bitrate limits! - // TODO limit transcoder number by user? - - if (_transcoders.size() + 1 > _maxTranscoders) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Transcoder limit reached!" << std::endl; - // Just answer an empty response, dont delete existing trasncode jobs - return true; - } - - try - { - Wt::Dbo::Transaction transaction( _db.getSession()); - - Database::Track::pointer track = Database::Track::getById( _db.getSession(), request.track_id() ); - if (!track) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Requested track does not exist" << std::endl; - // Track does no longer exist, just answer an empty response - return true; - } - - Transcode::InputMediaFile inputFile(track->getPath()); - Transcode::Parameters parameters(inputFile, Transcode::Format::get( format )); - parameters.setBitrate( Transcode::Stream::Audio, bitrate); - - std::shared_ptr transcoder = std::make_shared( parameters ); - - // now get a unique id (relative to this connection!) - uint32_t handle = _curHandle++; - assert(_transcoders.find(handle) == _transcoders.end()); - - _transcoders[handle] = transcoder; - - response.set_handle(handle); - - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Set up new transcode, handle = " << handle; - } - catch(std::exception& e) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Caught exception: " << e.what(); - return false; - } - - return true; -} - -bool -MediaRequestHandler::processGetPart(const MediaRequest::GetPart& request, MediaResponse::PartResult& response) -{ - std::size_t dataSize = request.requested_data_size(); - std::vector data; - if (dataSize > _maxPartSize) - dataSize = _maxPartSize; - - TranscoderMap::iterator itTranscoder = _transcoders.find(request.handle()); - if (itTranscoder == _transcoders.end()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No transcoder found for handle " << request.handle(); - return true; - } - - std::shared_ptr transcoder = itTranscoder->second; - - if (!transcoder->isComplete()) - { - data.reserve(dataSize); - transcoder->process(data, dataSize); - } - - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "MediaRequestHandler::processGetPart, handle = " << request.handle() << ", isComplete = " << std::boolalpha << transcoder->isComplete() << ", size = " << data.size(); - - std::copy(data.begin(), data.end(), std::back_inserter(*response.mutable_data())); - - return true; -} - - -bool -MediaRequestHandler::processTerminate(const MediaRequest::Terminate& request, MediaResponse::TerminateResult& response) -{ - LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "MediaRequestHandler: resetting transcoder for handle " << request.handle(); - - if (_transcoders.find(request.handle()) == _transcoders.end()) - { - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "No transcoder found for handle " << request.handle(); - return true; - } - else - { - _transcoders.erase(request.handle()); - } - - return true; -} - - - -} // namespace LmsAPI -} // namespace Server - - diff --git a/src/lms-api/server/MediaRequestHandler.hpp b/src/lms-api/server/MediaRequestHandler.hpp deleted file mode 100644 index f3f30c20..00000000 --- a/src/lms-api/server/MediaRequestHandler.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_MEDIA_REQUEST_HANDLER -#define REMOTE_MEDIA_REQUEST_HANDLER - -#include -#include - -#include "database/DatabaseHandler.hpp" -#include "transcode/AvConvTranscoder.hpp" - -#include "media.pb.h" - -namespace LmsAPI { -namespace Server { - -class MediaRequestHandler -{ - public: - MediaRequestHandler(Database::Handler& db); - - bool process(const MediaRequest& request, MediaResponse& response); - - private: - - bool processAudioPrepare(const MediaRequest::Prepare::Audio& request, MediaResponse::PrepareResult& response); - bool processGetPart(const MediaRequest::GetPart& request, MediaResponse::PartResult& response); - bool processTerminate(const MediaRequest::Terminate& request, MediaResponse::TerminateResult& response); - -// bool processVideoPrepare(const AudioCollectionRequest::GetGenreList& request, AudioCollectionResponse::GenreList& response); - - typedef std::map > TranscoderMap; - - TranscoderMap _transcoders; - - Database::Handler& _db; - - uint32_t _curHandle = 0; - - static const std::size_t _maxPartSize = 65536 - 128; - static const std::size_t _maxTranscoders = 1; -}; - -} // namespace Server -} // namespace LmsAPI - -#endif - diff --git a/src/lms-api/server/RequestHandler.cpp b/src/lms-api/server/RequestHandler.cpp deleted file mode 100644 index 861a14d7..00000000 --- a/src/lms-api/server/RequestHandler.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include "logger/Logger.hpp" - -#include "RequestHandler.hpp" - -namespace LmsAPI { -namespace Server { - -RequestHandler::RequestHandler(Wt::Dbo::SqlConnectionPool &connectionPool) -: _db( connectionPool ), -_authRequestHandler(_db), -_audioCollectionRequestHandler(_db), -_mediaRequestHandler(_db) -{ -} - -RequestHandler::~RequestHandler() -{ - // TODO manually log out user if needed? - _db.getLogin().logout(); -} - -bool -RequestHandler::process(const ClientMessage& request, ServerMessage& response) -{ - bool res = false; - - switch(request.type()) - { - - case ClientMessage::AuthRequest: - if (request.has_auth_request()) - { - res = _authRequestHandler.process(request.auth_request(), *response.mutable_auth_response()); - if (res) - response.set_type(ServerMessage::AuthResponse); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad ClientMessage::AuthRequest !"; - break; - case ClientMessage::AudioCollectionRequest: - // Not allowed if the user is not logged in - if (_db.getLogin().loggedIn()) - { - if (request.has_audio_collection_request()) - { - res = _audioCollectionRequestHandler.process(request.audio_collection_request(), *response.mutable_audio_collection_response()); - if (res) - response.set_type( ServerMessage::AudioCollectionResponse); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Bad ClientMessage::AudioCollectionRequest message!"; - } - break; - - case ClientMessage::MediaRequest: - // Not allowed if the user is not logged in - if (_db.getLogin().loggedIn()) - { - if (request.has_media_request()) - { - res = _mediaRequestHandler.process(request.media_request(), *response.mutable_media_response()); - if (res) - response.set_type( ServerMessage::MediaResponse); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Malformed ClientMessage::MediaRequest message!"; - } - break; - - default: - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "Unhandled message type = " << request.type(); - } - - return res; -} - - -} // namespace Server -} // namespace LmsAPI - - - diff --git a/src/lms-api/server/RequestHandler.hpp b/src/lms-api/server/RequestHandler.hpp deleted file mode 100644 index 9db747f4..00000000 --- a/src/lms-api/server/RequestHandler.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_REQUEST_HANDLER -#define REMOTE_REQUEST_HANDLER - -#include - -#include "messages.pb.h" - -#include "database/DatabaseHandler.hpp" - -#include "AuthRequestHandler.hpp" -#include "AudioCollectionRequestHandler.hpp" -#include "MediaRequestHandler.hpp" - -namespace LmsAPI { -namespace Server { - -class RequestHandler -{ - public: - - RequestHandler(Wt::Dbo::SqlConnectionPool& connectionPool); - ~RequestHandler(); - - bool process(const ClientMessage& request, ServerMessage& response); - - private: - - Database::Handler _db; - - AuthRequestHandler _authRequestHandler; - AudioCollectionRequestHandler _audioCollectionRequestHandler; - MediaRequestHandler _mediaRequestHandler; -}; - -} // namespace Server -} // namespace LmsAPI - -#endif - diff --git a/src/lms-api/server/Server.cpp b/src/lms-api/server/Server.cpp deleted file mode 100644 index f7292d10..00000000 --- a/src/lms-api/server/Server.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - - -#include - -#include -#include - -#include "logger/Logger.hpp" - -#include "Server.hpp" - -namespace LmsAPI { -namespace Server { - -Server::Server(const endpoint_type& bindEndpoint, - boost::filesystem::path certPath, - boost::filesystem::path privKeyPath, - boost::filesystem::path dhPath, - Wt::Dbo::SqlConnectionPool& connectionPool) -: -_acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/), -_connectionManager(), -_context(boost::asio::ssl::context::tlsv1_server), -_connectionPool(connectionPool) -{ - _ioService.setThreadCount(1); // TODO parametrize - - _context.set_options( boost::asio::ssl::context::default_workarounds // TODO check this thing - | boost::asio::ssl::context::single_dh_use - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::no_sslv3 - ); -// context_.set_password_callback(boost::bind(&server::get_password, this)); - _context.use_certificate_chain_file(certPath.string()); - _context.use_private_key_file(privKeyPath.string(), boost::asio::ssl::context::pem); - _context.use_tmp_dh_file(dhPath.string()); -} - -void -Server::start() -{ - // While the server is running, there is always at least one - // asynchronous operation outstanding: the asynchronous accept call waiting - // for new incoming connections. - asyncAccept(); - - _ioService.start(); -} - -void -Server::asyncAccept() -{ - std::shared_ptr newConnection = std::make_shared(_ioService, _context, _connectionManager, _connectionPool); - - _acceptor.async_accept(newConnection->getSocket(), - boost::bind(&Server::handleAccept, this, newConnection, boost::asio::placeholders::error)); -} - -void -Server::handleAccept(std::shared_ptr newConnection, boost::system::error_code ec) -{ - // Check whether the server was stopped before this - // completion handler had a chance to run. - if (!_acceptor.is_open()) - { - return; - } - - if (!ec) - { - _connectionManager.start(newConnection); - - // Accept another connection - // TODO: add some limit? - asyncAccept(); - } - else - LMS_LOG(MOD_REMOTE, SEV_ERROR) << "handleAccept: " << ec.message(); -} - - -void -Server::stop() -{ - // The server is stopped by cancelling all outstanding asynchronous - // operations. - _acceptor.close(); - _connectionManager.stopAll(); - - _ioService.stop(); -} - -} // namespace Server -} // namespace LmsAPI diff --git a/src/lms-api/server/Server.hpp b/src/lms-api/server/Server.hpp deleted file mode 100644 index e92c9384..00000000 --- a/src/lms-api/server/Server.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#ifndef REMOTE_SERVER_HPP -#define REMOTE_SERVER_HPP - -#include -#include - -#include -#include - -#include - -#include "Connection.hpp" -#include "ConnectionManager.hpp" - -#include "RequestHandler.hpp" - -namespace LmsAPI { -namespace Server { - -class Server -{ - public: - - Server(const Server&) = delete; - Server& operator=(const Server&) = delete; - - typedef boost::asio::ip::tcp::endpoint endpoint_type; - - // Serve up data from the given database - Server(const endpoint_type& bindEndpoint, - boost::filesystem::path certPath, - boost::filesystem::path privKeyPath, - boost::filesystem::path dhPath, - Wt::Dbo::SqlConnectionPool& connectionPool); - - // Run the server's io_service loop. - void start(); - - void stop(); - - private: - /// Perform an asynchronous accept operation. - void asyncAccept(); - void handleAccept(std::shared_ptr newConnection, boost::system::error_code ec); - - Wt::WIOService _ioService; - - /// Acceptor used to listen for incoming connections. - boost::asio::ip::tcp::acceptor _acceptor; - - /// The connection manager which owns all live connections. - ConnectionManager _connectionManager; - - boost::asio::ssl::context _context; - - /// The database to be used for requests - Wt::Dbo::SqlConnectionPool& _connectionPool; -}; - -} // namespace Server -} // namespace LmsAPI - -#endif diff --git a/src/service/DatabaseUpdateService.cpp b/src/service/DatabaseUpdateService.cpp index df201019..e540a0b3 100644 --- a/src/service/DatabaseUpdateService.cpp +++ b/src/service/DatabaseUpdateService.cpp @@ -19,8 +19,6 @@ #include -#include "config/ConfigReader.hpp" - #include "DatabaseUpdateService.hpp" namespace Service { diff --git a/test/CheckDbBasics.cpp b/test/CheckDbBasics.cpp index 83267eb8..c993105b 100644 --- a/test/CheckDbBasics.cpp +++ b/test/CheckDbBasics.cpp @@ -50,7 +50,7 @@ int main(void) track.modify()->setArtist(artist); track.modify()->setRelease(release); - track.modify()->setGenres( { genre }); + track.modify()->setGenres( std::vector({ genre })); } // Search diff --git a/test/Makefile.am b/test/Makefile.am index 60d0f137..8b5e4a48 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,35 +3,8 @@ TESTS = database-basics database-integrity sql-query database-user check_PROGRAMS = database-basics database-integrity sql-query database-user -if LMSAPI -TESTS += remote-client -check_PROGRAMS += remote-client - -remote_client_SOURCES = \ - $(srcdir)/RemoteClient.cpp - -nodist_remote_client_SOURCES = \ - $(builddir)/auth.pb.cc \ - $(builddir)/collection.pb.cc \ - $(builddir)/media.pb.cc \ - $(builddir)/messages.pb.cc - -BUILT_SOURCES = \ - $(builddir)/auth.pb.h \ - $(builddir)/collection.pb.h \ - $(builddir)/media.pb.h \ - $(builddir)/messages.pb.h - -remote_client_CXXFLAGS=-std=c++11 -Wall -Wextra -DBOOST_LOG_DYN_LINK -I$(top_srcdir)/src - -%.pb.cc %.pb.h: $(top_srcdir)/lms-api/proto/%.proto - $(PROTOC) --proto_path=$(top_srcdir)/lms-api/proto/ --cpp_out=$(builddir)/ $^ - -endif - database_basics_SOURCES = \ $(srcdir)/CheckDbBasics.cpp \ - $(top_srcdir)/src/config/ConfigReader.cpp \ $(top_srcdir)/src/logger/Logger.cpp \ $(top_srcdir)/src/database/Artist.cpp \ $(top_srcdir)/src/database/DatabaseHandler.cpp \ @@ -48,7 +21,6 @@ database_basics_CXXFLAGS=-std=c++11 -Wall -Wextra -DBOOST_LOG_DYN_LINK -I$(top_s database_user_SOURCES = \ $(srcdir)/CheckDatabaseUser.cpp \ - $(top_srcdir)/src/config/ConfigReader.cpp \ $(top_srcdir)/src/logger/Logger.cpp \ $(top_srcdir)/src/database/Artist.cpp \ $(top_srcdir)/src/database/Playlist.cpp \ @@ -66,7 +38,6 @@ database_user_CXXFLAGS=-std=c++11 -Wall -Wextra -DBOOST_LOG_DYN_LINK -I$(top_src database_integrity_SOURCES = \ $(srcdir)/DatabaseIntegrity.cpp \ - $(top_srcdir)/src/config/ConfigReader.cpp \ $(top_srcdir)/src/logger/Logger.cpp \ $(top_srcdir)/src/database/Artist.cpp \ $(top_srcdir)/src/database/Playlist.cpp \ diff --git a/test/RemoteClient.cpp b/test/RemoteClient.cpp deleted file mode 100644 index 062547fb..00000000 --- a/test/RemoteClient.cpp +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS 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 3 of the License, or - * (at your option) any later version. - * - * LMS 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 LMS. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lms-api/messages/Header.hpp" -#include "messages.pb.h" - -#include "TestDatabase.hpp" - -struct GenreInfo -{ - uint64_t id; - std::string name; - - GenreInfo() : id(0) {} -}; - -std::ostream& operator<<(std::ostream& os, const GenreInfo& info) -{ - os << "name = '" << info.name << "'(" << info.id << ")"; - return os; -} - -struct ArtistInfo -{ - uint64_t id; - std::string mbid; - std::string name; - - ArtistInfo() :id(0) {} -}; - -std::ostream& operator<<(std::ostream& os, const ArtistInfo& info) -{ - os << "name = '" << info.name << "'(" << info.id << ")"; - return os; -} - -struct ReleaseInfo -{ - uint64_t id; - std::string mbid; - std::string name; - - ReleaseInfo() : id(0) {} -}; - -std::ostream& operator<<(std::ostream& os, const ReleaseInfo& info) -{ - os << "name = '" << info.name << "'(" << info.id << ")"; - return os; -} - -struct TrackInfo -{ - uint64_t id; - std::string mbid; - - uint64_t release_id; - uint64_t artist_id; - std::vector genre_id; - - uint32_t disc_number; - uint32_t track_number; - - std::string name; - - boost::posix_time::time_duration duration; - - std::string date; - std::string original_date; - - TrackInfo(): id(0), release_id(0), artist_id(0), disc_number(0), track_number(0) {} -}; - -std::ostream& operator<<(std::ostream& os, const TrackInfo& info) -{ - os << "id = " << info.id << ", name = '" << info.name << "', track_number = " << info.track_number << ", duration = " << info.duration; - if (!info.date.empty()) - os << ", date = " << info.date; - if (!info.original_date.empty()) - os << ", original date = " << info.original_date; - - return os; -} - -struct Cover -{ - std::string mimeType; - std::vector data; -}; - -struct SearchFilter -{ - std::vector artistIds; - std::vector genreIds; - std::vector releaseIds; - std::vector trackIds; -}; - -void SearchFilterToRequest(const SearchFilter& filter, LmsAPI::AudioCollectionRequest_SearchFilter& request) -{ - for (uint64_t id : filter.artistIds) - request.add_artist_id(id); - - for (uint64_t id : filter.genreIds) - request.add_genre_id(id); - - for (uint64_t id : filter.releaseIds) - request.add_release_id(id); - - for (uint64_t id : filter.trackIds) - request.add_track_id(id); -} - -// Ugly class for testing purposes -class TestClient -{ - public: - TestClient(boost::asio::ip::tcp::endpoint endpoint) - : _context(boost::asio::ssl::context::sslv23), // be large on this - _socket(_ioService, _context) - { - boost::asio::ip::tcp::resolver resolver(_ioService); - - _socket.set_verify_mode(boost::asio::ssl::verify_peer); - _socket.set_verify_callback(boost::bind(&TestClient::verifyCertificate, this, _1, _2)); - - boost::asio::connect(_socket.lowest_layer(), resolver.resolve(endpoint)); - - _socket.handshake(boost::asio::ssl::stream_base::client); - } - - void getArtists(std::vector& artists, const SearchFilter& filter = SearchFilter()) - { - - const std::size_t requestedBatchSize = 128; - std::size_t offset = 0; - std::size_t res = 0; - - - while ((res = getArtists(artists, filter, offset, requestedBatchSize) ) > 0) - offset += res; - - } - - std::size_t getArtists(std::vector& artists, const SearchFilter& filter, std::size_t offset, std::size_t size) - { - std::size_t nbArtists = 0; - - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage_Type_AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest_Type_TypeGetArtistList); - request.mutable_audio_collection_request()->mutable_get_artists()->mutable_batch_parameter()->set_size(size); - request.mutable_audio_collection_request()->mutable_get_artists()->mutable_batch_parameter()->set_offset(offset); - SearchFilterToRequest(filter, *request.mutable_audio_collection_request()->mutable_get_artists()->mutable_search_filter()); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - if (!response.audio_collection_response().has_artist_list()) - throw std::runtime_error("not an artist_list!"); - - for (int i = 0; i < response.audio_collection_response().artist_list().artists_size(); ++i) - { - const LmsAPI::AudioCollectionResponse_Artist& respArtist = response.audio_collection_response().artist_list().artists(i); - - if (!respArtist.has_id()) - throw std::runtime_error("no id!"); - if (!respArtist.has_name()) - throw std::runtime_error("no artist name!"); - - ArtistInfo artist; - artist.name = respArtist.name(); - artist.id = respArtist.id(); - if (respArtist.has_mbid()) - artist.mbid = respArtist.mbid(); - - artists.push_back( artist ); - nbArtists++; - } - - return nbArtists; - } - - void getGenres(std::vector& genres, const SearchFilter& filter = SearchFilter()) - { - - const std::size_t requestedBatchSize = 8; - std::size_t offset = 0; - std::size_t res = 0; - - while ((res = getGenres(genres, filter, offset, requestedBatchSize) ) > 0) - offset += res; - - } - - std::size_t getGenres(std::vector& genres, const SearchFilter& filter, std::size_t offset, std::size_t size) - { - std::size_t nbAdded = 0; - - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage_Type_AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest_Type_TypeGetGenreList); - request.mutable_audio_collection_request()->mutable_get_genres()->mutable_batch_parameter()->set_size(size); - request.mutable_audio_collection_request()->mutable_get_genres()->mutable_batch_parameter()->set_offset(offset); - SearchFilterToRequest(filter, *request.mutable_audio_collection_request()->mutable_get_genres()->mutable_search_filter()); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - if (!response.audio_collection_response().has_genre_list()) - throw std::runtime_error("not an genre_list!"); - - for (int i = 0; i < response.audio_collection_response().genre_list().genres_size(); ++i) - { - const LmsAPI::AudioCollectionResponse_Genre& respGenre = response.audio_collection_response().genre_list().genres(i); - - if (!respGenre.has_id()) - throw std::runtime_error("no genre id!"); - if (!respGenre.has_name()) - throw std::runtime_error("no genre name!"); - - GenreInfo genre; - genre.id = respGenre.id(); - genre.name = respGenre.name(); - - genres.push_back( genre ); - nbAdded++; - } - return nbAdded; - } - - void getReleases(std::vector& releases, const SearchFilter& filter = SearchFilter()) - { - - const std::size_t requestedBatchSize = 256; - std::size_t offset = 0; - std::size_t res = 0; - - while ((res = getReleases(releases, filter, offset, requestedBatchSize) ) > 0) - offset += res; - - } - - std::size_t getReleases(std::vector& releases, const SearchFilter& filter, std::size_t offset, std::size_t size) - { - std::size_t nbAdded = 0; - - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage_Type_AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest_Type_TypeGetReleaseList); - request.mutable_audio_collection_request()->mutable_get_releases()->mutable_batch_parameter()->set_size(size); - request.mutable_audio_collection_request()->mutable_get_releases()->mutable_batch_parameter()->set_offset(offset); - SearchFilterToRequest(filter, *request.mutable_audio_collection_request()->mutable_get_releases()->mutable_search_filter()); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.audio_collection_response().has_type()) - throw std::runtime_error("Missing type!"); - -// if (!response.audio_collection_response().type() != LmsAPI::ServerMessage::AudioCollectionResponse::TypeReleaseList) -// throw std::runtime_error("Bad type!"); - - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - if (!response.audio_collection_response().has_release_list()) - throw std::runtime_error("not an release list!"); - - for (int i = 0; i < response.audio_collection_response().release_list().releases_size(); ++i) - { - const LmsAPI::AudioCollectionResponse_Release& respRelease = response.audio_collection_response().release_list().releases(i); - - if (!respRelease.has_id()) - throw std::runtime_error("no id!"); - if (!respRelease.has_name()) - throw std::runtime_error("no release name!"); - - ReleaseInfo release; - release.id = respRelease.id(); - release.name = respRelease.name(); - - releases.push_back( release ); - nbAdded++; - } - return nbAdded; - } - - void getTracks(std::vector& tracks, const SearchFilter& filter = SearchFilter()) - { - const std::size_t requestedBatchSize = 0; - std::size_t offset = 0; - std::size_t res = 0; - - while ((res = getTracks(tracks, filter, offset, requestedBatchSize) ) > 0) - offset += res; - } - - std::size_t getTracks(std::vector& tracks, const SearchFilter& filter, std::size_t offset, std::size_t size) - { - std::size_t nbAdded = 0; - - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage_Type_AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest_Type_TypeGetTrackList); - request.mutable_audio_collection_request()->mutable_get_tracks()->mutable_batch_parameter()->set_size(size); - request.mutable_audio_collection_request()->mutable_get_tracks()->mutable_batch_parameter()->set_offset(offset); - SearchFilterToRequest(filter, *request.mutable_audio_collection_request()->mutable_get_tracks()->mutable_search_filter()); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - if (!response.audio_collection_response().has_track_list()) - throw std::runtime_error("not an track list!"); - - for (int i = 0; i < response.audio_collection_response().track_list().tracks_size(); ++i) - { - const LmsAPI::AudioCollectionResponse_Track& respTrack = response.audio_collection_response().track_list().tracks(i);; - - TrackInfo track; - track.id = respTrack.id(); - if (respTrack.has_mbid()) - track.mbid = respTrack.mbid(); - - track.name = respTrack.name(); - track.duration = boost::posix_time::seconds(respTrack.duration_secs()); - - if (respTrack.has_track_number()) - track.track_number = respTrack.track_number(); - - if (respTrack.has_disc_number()) - track.disc_number = respTrack.disc_number(); - - if (respTrack.has_release_date()) - track.date = respTrack.release_date(); - - if (respTrack.has_original_release_date()) - track.original_date = respTrack.original_release_date(); - - - tracks.push_back( track ); - nbAdded++; - } - - return nbAdded; - } - - - void getMediaAudio(uint64_t audioId, std::vector& data) - { - - // Prepare - uint32_t handle = mediaAudioPrepare( audioId ); - - // Get while available - mediaGet( handle, data ); - - // Terminate - mediaTerminate( handle ); - } - - void getCoverTrack(std::vector& coverArt, uint64_t trackId) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest::TypeGetCoverArt); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_type( LmsAPI::AudioCollectionRequest::GetCoverArt::TypeGetCoverArtTrack); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_track_id( trackId ); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_size( 256 ); - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - for (int i = 0; i < response.audio_collection_response().cover_art_size(); ++i) - { - Cover cover; - cover.mimeType = response.audio_collection_response().cover_art(i).mime_type(); - cover.data.assign(response.audio_collection_response().cover_art(i).data().begin(), response.audio_collection_response().cover_art(i).data().end());; - - coverArt.push_back(cover); - } - } - - void getCoverRelease(std::vector& coverArt, uint64_t releaseId) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest::TypeGetCoverArt); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_type( LmsAPI::AudioCollectionRequest::GetCoverArt::TypeGetCoverArtRelease); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_release_id( releaseId ); - request.mutable_audio_collection_request()->mutable_get_cover_art()->set_size( 256 ); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - for (int i = 0; i < response.audio_collection_response().cover_art_size(); ++i) - { - Cover cover; - cover.mimeType = response.audio_collection_response().cover_art(i).mime_type(); - cover.data.assign(response.audio_collection_response().cover_art(i).data().begin(), response.audio_collection_response().cover_art(i).data().end());; - - coverArt.push_back(cover); - } - - } - - std::string getRevision(void) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::AudioCollectionRequest ); - - request.mutable_audio_collection_request()->set_type( LmsAPI::AudioCollectionRequest::TypeGetRevision); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_audio_collection_response()) - throw std::runtime_error("not an audio_collection_response!"); - - if (!response.audio_collection_response().has_revision()) - throw std::runtime_error("not a revision!"); - - return response.audio_collection_response().revision().rev(); - } - - bool login(const std::string& username, const std::string& password) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::AuthRequest ); - - request.mutable_auth_request()->set_type( LmsAPI::AuthRequest::TypePassword); - request.mutable_auth_request()->mutable_password()->set_user_login( username ); - request.mutable_auth_request()->mutable_password()->set_user_password( password ); - - sendMsg(request); - - // Receive responses - LmsAPI::ServerMessage response; - recvMsg(response); - - // Process message - if (!response.has_auth_response()) - throw std::runtime_error("not an auth response!"); - - if (!response.auth_response().has_password_result()) - throw std::runtime_error("not a password result!"); - - switch( response.auth_response().password_result().type()) - { - case LmsAPI::AuthResponse::PasswordResult::TypePasswordValid: - return true; - case LmsAPI::AuthResponse::PasswordResult::TypePasswordInvalid: - return false; - case LmsAPI::AuthResponse::PasswordResult::TypeLoginThrottling: - if (response.auth_response().password_result().has_delay()) - std::cerr << "Has to wait for " << response.auth_response().password_result().delay() << " seconds" << std::endl; - - return false; - default: - throw std::runtime_error("bad password result type"); - } - } - - private: - - bool verifyCertificate(bool preverified, boost::asio::ssl::verify_context& ctx) - { - // In this example we will simply print the certificate's subject name. - std::array subject_name; - - X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); - X509_NAME_oneline(X509_get_subject_name(cert), subject_name.data(), subject_name.size()); - - std::cout << "Verifying '" << std::string(subject_name.data()) << "', preverified = " << std::boolalpha << preverified << std::endl; - - return true; // preverified; - } - - uint32_t mediaAudioPrepare(uint64_t audioId) - { - - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage_Type_MediaRequest); - - request.mutable_media_request()->set_type( LmsAPI::MediaRequest_Type_TypeMediaPrepare); - request.mutable_media_request()->mutable_prepare()->set_type(LmsAPI::MediaRequest_Prepare_Type_AudioRequest); - - // Set fields - request.mutable_media_request()->mutable_prepare()->mutable_audio()->set_track_id( audioId ); - request.mutable_media_request()->mutable_prepare()->mutable_audio()->set_codec_type( LmsAPI::MediaRequest::Prepare::AudioCodecTypeOGA ); - request.mutable_media_request()->mutable_prepare()->mutable_audio()->set_bitrate( LmsAPI::MediaRequest::Prepare::AudioBitrate_64_kbps ); - - std::cout << "Sending prepare request" << std::endl; - sendMsg(request); - - std::cout << "Waiting for response" << std::endl; - // Receive response - LmsAPI::ServerMessage response; - recvMsg(response); - - std::cout << "Got a response" << std::endl; - - // Process message - if (!response.has_media_response()) - throw std::runtime_error("Preapre: not an media reponse!"); - - if (!response.media_response().has_prepare_result()) - throw std::runtime_error("Prepare: not an prepare result msg!"); - - if (!response.media_response().prepare_result().has_handle()) - throw std::runtime_error("Prepare: cannot get handle"); - - return response.media_response().prepare_result().handle(); - } - - void mediaGet(uint32_t handle, std::vector& data) - { - while (mediaGetPart(handle, data) > 0) - ; - } - - - std::size_t mediaGetPart(uint32_t handle, std::vector& data) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::MediaRequest); - - request.mutable_media_request()->set_type( LmsAPI::MediaRequest::TypeMediaGetPart); - request.mutable_media_request()->mutable_get_part()->set_handle(handle); - request.mutable_media_request()->mutable_get_part()->set_requested_data_size(65536); - - std::cout << "Sending GetPart request" << std::endl; - sendMsg(request); - - std::cout << "Waiting for response" << std::endl; - // Receive response - LmsAPI::ServerMessage response; - recvMsg(response); - - std::cout << "Got a response" << std::endl; - - if (!response.has_media_response()) - throw std::runtime_error("not an media response"); - - // Process message - if (response.media_response().type() != LmsAPI::MediaResponse::TypePartResult) - throw std::runtime_error("GetPart: not a Part response!"); - - if (!response.media_response().has_part_result()) - throw std::runtime_error("GetPart: does not have a Part result!"); - - std::copy(response.media_response().part_result().data().begin(), response.media_response().part_result().data().end(), std::back_inserter(data)); - - return response.media_response().part_result().data().size(); - } - - void mediaTerminate( uint32_t handle ) - { - // Send request - LmsAPI::ClientMessage request; - - request.set_type( LmsAPI::ClientMessage::MediaRequest); - - request.mutable_media_request()->set_type( LmsAPI::MediaRequest::TypeMediaTerminate); - request.mutable_media_request()->mutable_terminate()->set_handle(handle); - - sendMsg(request); - - // Receive response - LmsAPI::ServerMessage response; - recvMsg(response); - - - // Process message - if (!response.has_media_response()) - throw std::runtime_error("Terminate: not an media response"); - - if (!response.media_response().has_terminate_result()) - throw std::runtime_error("Terminate: not an terminate msg!"); - - } - - - void sendMsg(const ::google::protobuf::Message& message) - { - std::ostream os(&_outputStreamBuf); - - // Serialize message - if (message.SerializeToOstream(&os)) - { - - if (_outputStreamBuf.size() > LmsAPI::Header::max_data_size) - { - std::ostringstream oss; oss << "Message too big = " << _outputStreamBuf.size() << " bytes! (max is " << LmsAPI::Header::max_data_size << ")" << std::endl; - throw std::runtime_error("Message to big!"); - } - - // Send message header - std::array headerBuffer; - - // Generate header content - { - LmsAPI::Header header; - header.setDataSize(_outputStreamBuf.size()); - header.to_buffer(headerBuffer); - } - - boost::asio::write(_socket, boost::asio::buffer(headerBuffer)); - - // Send serialized message - std::size_t n = boost::asio::write(_socket, - _outputStreamBuf.data(), - boost::asio::transfer_exactly(_outputStreamBuf.size())); - assert(n == _outputStreamBuf.size()); - - _outputStreamBuf.consume(n); - - } - else - { - std::cerr << "Cannot serialize message!" << std::endl; - throw std::runtime_error("message.SerializeToString failed!"); - } - - } - - void recvMsg(::google::protobuf::Message& message) - { - std::istream is(&_inputStreamBuf); - - { - // reserve bytes in output sequence - boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(LmsAPI::Header::size); - - std::size_t n = boost::asio::read(_socket, - bufs, - boost::asio::transfer_exactly(LmsAPI::Header::size)); - - assert(n == LmsAPI::Header::size); - _inputStreamBuf.commit(n); - - } - - LmsAPI::Header header; - if (!header.from_istream(is)) - throw std::runtime_error("Cannot read header from buffer!"); - - // Read in a stream buffer - { - // reserve bytes in output sequence - boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(header.getDataSize()); - - std::size_t n = boost::asio::read(_socket, - bufs, - boost::asio::transfer_exactly(header.getDataSize())); - - assert(n == header.getDataSize()); - _inputStreamBuf.commit(n); - - if (!message.ParseFromIstream(&is)) - throw std::runtime_error("message.ParseFromIstream failed!"); - - } - } - - typedef boost::asio::ssl::stream ssl_socket; - - boost::asio::io_service _ioService; - boost::asio::ssl::context _context; - ssl_socket _socket; - - boost::asio::streambuf _inputStreamBuf; - boost::asio::streambuf _outputStreamBuf; - -}; - -enum class Test { - ArtistFilters, - ReleaseFilterArtist, - ReleaseFilterGenre, - TrackFilters, - CoverByTrack, - CoverByRelease, - Transcode, -}; - -/* Uncomment test to be disabled */ -std::set tests = { - Test::ArtistFilters, - Test::ReleaseFilterArtist, - Test::ReleaseFilterGenre, - Test::TrackFilters, -// Test::CoverByTrack, - Test::CoverByRelease, -// Test::Transcode, -}; - -bool test(Test t) -{ - return (tests.find(t) != tests.end()); -} - -int main() -{ - try { - bool writeCovers = false; - - std::cout << "Running test..." << std::endl; - - // Client - // connect to loopback TODO parametrize - TestClient client( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4::loopback(), 5080)); - - // Use a dumb account in order to login TODO parametrize - if (!client.login("admin", "totoadmin")) - throw std::runtime_error("login failed!"); - - // **** REVISION *** - std::cout << "Getting revision..." << std::endl; - std::string rev = client.getRevision(); - std::cout << "Revision '" << rev << "'" << std::endl; - - // ****** Artists ********* - std::cout << "Getting artists..." << std::endl; - std::vector artists; - client.getArtists(artists); - - std::cout << "Got " << artists.size() << " artists!" << std::endl; - for (const ArtistInfo& artist : artists) - std::cout << "Artist: '" << artist << "'" << std::endl; - - // ***** Genres ********* - std::cout << "Getting genres..." << std::endl; - std::vector genres; - client.getGenres(genres); - - std::cout << "Got " << genres.size() << " genres!" << std::endl; - for (const GenreInfo& genre : genres) - std::cout << "Genre: '" << genre << "'" << std::endl; - - // **** Releases ****** - std::cout << "Getting releases..." << std::endl; - std::vector releases; - client.getReleases(releases); - for (const ReleaseInfo& release : releases) - std::cout << "Release: '" << release << "'" << std::endl; - - // **** Tracks ****** - std::cout << "Getting tracks..." << std::endl; - std::vector tracks; - client.getTracks(tracks); - - std::cout << "Got " << tracks.size() << " tracks!" << std::endl; - for (const TrackInfo& track : tracks) - std::cout << "Track: '" << track << "'" << std::endl; - - // Caution: long test! - if (test(Test::ArtistFilters)) - { - std::cout << "Getting artist for each genre..." << std::endl; - // Get the artists for each genre - for (const GenreInfo& genre : genres) - { - std::cout << "Getting artists from genre '" << genre.name << "'... "; - SearchFilter filter; - filter.genreIds.push_back(genre.id); - - std::vector artists; - client.getArtists(artists, filter); - - std::cout << "Found " << artists.size() << " artists!" << std::endl; - for (const ArtistInfo& artist : artists) - std::cout << "Genre '" << genre.name << "' -> Artist: " << artist << std::endl; - } - } - - if (test(Test::ReleaseFilterArtist)) - { - std::cout << "Getting release for each artist..." << std::endl; - for (const ArtistInfo& artist : artists) - { - std::cout << "Getting release from artist '" << artist.name << "'... "; - SearchFilter filter; - filter.artistIds.push_back(artist.id); - - std::vector releases; - client.getReleases(releases, filter); - - std::cout << "Found " << releases.size() << " releases!" << std::endl; - for (const ReleaseInfo& release : releases) - std::cout << "Artist '" << artist.name << "' -> Release: '" << release << "'" << std::endl; - } - } - - if (test(Test::ReleaseFilterGenre)) - { - std::cout << "Getting release for each genre..." << std::endl; - for (const GenreInfo& genre : genres) - { - std::cout << "Getting release from genre '" << genre.name << "'... "; - SearchFilter filter; - filter.genreIds.push_back(genre.id); - - std::vector releases; - client.getReleases(releases, filter); - - std::cout << "Found " << releases.size() << " releases!" << std::endl; - BOOST_FOREACH(const ReleaseInfo& release, releases) - std::cout << "Genre '" << genre.name << "' -> Release: '" << release << "'" << std::endl; - } - } - - if (test(Test::TrackFilters)) - { - std::cout << "Getting tracks for each artist..." << std::endl; - // Get the tracks for each artist - for (const ArtistInfo& artist : artists) - { - SearchFilter filter; - filter.artistIds.push_back(artist.id); - - std::vector tracks; - client.getTracks(tracks, filter); - - std::cout << "Artist '" << artist.name << "', nb tracks = " << tracks.size() << std::endl; - for (const TrackInfo& track : tracks) - std::cout << "Artist '" << artist.name << "', track: '" << track << "'" << std::endl; - } - } - - // ***** Covers ******* - if (test(Test::CoverByRelease)) - { - std::cout << "Getting cover for each release..." << std::endl; - for (const ReleaseInfo& release : releases) - { - std::vector coverArts; - client.getCoverRelease(coverArts, release.id); - - if (writeCovers) - { - boost::filesystem::create_directory("cover"); - for (const Cover coverArt : coverArts) - { - std::ostringstream oss; oss << "cover/" << release.name << ".jpeg"; - std::ofstream out(oss.str().c_str()); - for (unsigned char c : coverArt.data) - out.put(c); - } - } - - std::cout << "Release '" << release << "', spotted " << coverArts.size() << " covers!" << std::endl; - } - } - - if (test(Test::CoverByTrack)) - { - std::cout << "Getting cover for each track..." << std::endl; - for (const TrackInfo& track : tracks) - { - std::vector coverArt; - client.getCoverTrack(coverArt, track.id); - - std::cout << "Track '" << track << "', spotted " << coverArt.size() << " covers!" << std::endl; - } - - } - - if (test(Test::Transcode)) - { - for (const TrackInfo& track : tracks) - { - std::vector data; - client.getMediaAudio(track.id, data); - std::cout << "Media size = " << data.size() << std::endl; - } - } - - std::cout << "End of tests!" << std::endl; - } - catch(std::exception& e) - { - std::cerr << "Caught exception " << e.what() << std::endl; - return EXIT_FAILURE; - } - - std::cout << "Normal quit..." << std::endl; - return EXIT_SUCCESS; -} - -