├── .clang-format ├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── ChangeLog ├── Doxyfile ├── LICENSE ├── MIMOSA_VERSION ├── README ├── cmake ├── Bison.cmake ├── Flex.cmake ├── ProtocMimosa.cmake └── Tests.cmake ├── dist.sh ├── mimosa ├── CMakeLists.txt ├── archive │ ├── CMakeLists.txt │ ├── entry.hh │ ├── reader.cc │ ├── reader.hh │ ├── writer.cc │ └── writer.hh ├── bencode │ ├── CMakeLists.txt │ ├── bencode.doch │ ├── copy.cc │ ├── copy.hh │ ├── decoder.cc │ ├── decoder.hh │ ├── encoder.cc │ └── encoder.hh ├── bittorrent │ ├── CMakeLists.txt │ ├── torrent-descriptor.cc │ ├── torrent-descriptor.hh │ ├── torrent-parser.cc │ └── torrent-parser.hh ├── channel.hh ├── compat │ └── uio.hh ├── condition.hh ├── container-of.hh ├── cpu-count.cc ├── cpu-count.hh ├── cpu-foreach.hh ├── cpu-foreach.hxx ├── endian.hh ├── env.cc ├── env.hh ├── expiring-cache.hh ├── expiring-cache.hxx ├── fft │ ├── fft.hh │ ├── fft.hxx │ ├── normalize.hh │ ├── normalize.hxx │ ├── scwf-gen.cc │ ├── scwf-gen.hh │ └── scwf-gen.hxx ├── flat │ ├── CMakeLists.txt │ ├── flat.cc │ └── flat.hh ├── format │ ├── CMakeLists.txt │ ├── format-stream.hh │ ├── format.doch │ ├── format.hh │ ├── format.hxx │ ├── print.cc │ ├── print.hh │ ├── print.hxx │ └── tests │ │ ├── CMakeLists.txt │ │ ├── tst-format.cc │ │ └── tst-print.cc ├── fs │ ├── CMakeLists.txt │ ├── copy.cc │ ├── copy.hh │ ├── dir-iterator.cc │ ├── dir-iterator.hh │ ├── exists.cc │ ├── exists.hh │ ├── find.cc │ ├── find.hh │ ├── fs.doch │ ├── move.cc │ ├── move.hh │ ├── rm.cc │ └── rm.hh ├── function.hh ├── future.hh ├── future.hxx ├── git │ ├── CMakeLists.txt │ ├── archive.cc │ ├── archive.hh │ ├── blob.hh │ ├── commit.hh │ ├── diff.hh │ ├── patch.hh │ ├── reference.cc │ ├── reference.hh │ ├── repository.cc │ ├── repository.hh │ ├── revwalk.cc │ ├── revwalk.hh │ ├── tag.hh │ ├── tree-entry.hh │ ├── tree.cc │ └── tree.hh ├── http │ ├── .gitignore │ ├── CMakeLists.txt │ ├── byte-range.hh │ ├── chunked-stream.cc │ ├── chunked-stream.hh │ ├── client-channel.cc │ ├── client-channel.hh │ ├── coding.hh │ ├── cookie.cc │ ├── cookie.hh │ ├── crud-handler.cc │ ├── crud-handler.hh │ ├── dispatch-handler.cc │ ├── dispatch-handler.hh │ ├── docs.txt │ ├── error-handler.cc │ ├── error-handler.hh │ ├── fs-handler.cc │ ├── fs-handler.hh │ ├── handler.hh │ ├── host-handler.cc │ ├── host-handler.hh │ ├── http.doch │ ├── log-handler.cc │ ├── log-handler.hh │ ├── log.cc │ ├── log.hh │ ├── message-reader.hh │ ├── message-reader.hxx │ ├── message-writer.hh │ ├── message-writer.hxx │ ├── method-handler.cc │ ├── method-handler.hh │ ├── method.cc │ ├── method.hh │ ├── mime-db.cc │ ├── mime-db.hh │ ├── redirect.cc │ ├── redirect.hh │ ├── request-lexer.l │ ├── request-parser.y │ ├── request-reader.cc │ ├── request-reader.hh │ ├── request-writer.cc │ ├── request-writer.hh │ ├── request.cc │ ├── request.hh │ ├── response-reader.cc │ ├── response-reader.hh │ ├── response-writer.cc │ ├── response-writer.hh │ ├── response.cc │ ├── response.hh │ ├── samples │ │ ├── CMakeLists.txt │ │ ├── mget.cc │ │ ├── mpost.cc │ │ ├── mput.cc │ │ └── web-server.cc │ ├── server-channel.cc │ ├── server-channel.hh │ ├── server.cc │ ├── server.hh │ ├── status.cc │ ├── status.hh │ ├── tests │ │ ├── CMakeLists.txt │ │ ├── tst-request-parser.cc │ │ └── tst-response.cc │ ├── time.cc │ └── time.hh ├── init.cc ├── init.doch ├── init.hh ├── intrusive-dlist.hh ├── intrusive-hash-table.hh ├── intrusive-hash-table.hxx ├── intrusive-slist.hh ├── json │ ├── CMakeLists.txt │ ├── decoder.cc │ ├── decoder.hh │ ├── encoder.cc │ ├── encoder.hh │ └── tests │ │ ├── CMakeLists.txt │ │ ├── tst-decoder.cc │ │ └── tst-encoder.cc ├── kvs.hh ├── locker.hh ├── log │ ├── CMakeLists.txt │ ├── level.cc │ ├── level.hh │ ├── log.cc │ ├── log.hh │ ├── origin.cc │ ├── origin.hh │ └── tests │ │ ├── CMakeLists.txt │ │ └── hello-log.cc ├── mutex.hh ├── net │ ├── CMakeLists.txt │ ├── accept.cc │ ├── accept.hh │ ├── common.hh │ ├── connect.cc │ ├── connect.hh │ ├── io.cc │ ├── io.hh │ ├── print.cc │ ├── print.hh │ ├── server.cc │ └── server.hh ├── non-copyable.hh ├── non-movable.hh ├── options │ ├── CMakeLists.txt │ ├── options.cc │ ├── options.hh │ └── tests │ │ ├── CMakeLists.txt │ │ ├── duplicate-opts.cc │ │ └── hello-opts.cc ├── preproc.hh ├── priviledge-drop.cc ├── priviledge-drop.hh ├── process.cc ├── process.hh ├── recursive-mutex.hh ├── redis │ ├── CMakeLists.txt │ ├── context.hh │ ├── log.cc │ ├── log.hh │ ├── redis.hh │ └── reply.hh ├── ref-countable.hh ├── ref-counted-ptr.hh ├── rpc │ ├── CMakeLists.txt │ ├── basic-call.cc │ ├── basic-call.hh │ ├── bencode.cc │ ├── bencode.hh │ ├── call.hh │ ├── channel.cc │ ├── channel.hh │ ├── exception.hh │ ├── gen │ │ ├── CMakeLists.txt │ │ └── protoc-gen-mimosa.cc │ ├── http-call.cc │ ├── http-call.hh │ ├── json.cc │ ├── json.hh │ ├── log.cc │ ├── log.hh │ ├── protocol.hh │ ├── rpc.doch │ ├── samples │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── database.cc │ │ ├── database.hh │ │ ├── kv-db-client.cc │ │ ├── kv-db-http.cc │ │ ├── kv-db.cc │ │ └── kv-db.proto │ ├── server.cc │ ├── server.hh │ ├── service-map.cc │ ├── service-map.hh │ ├── service.cc │ └── service.hh ├── shared-locker.hh ├── shared-mutex.hh ├── singleton.hh ├── singleton.hxx ├── smtp │ ├── CMakeLists.txt │ ├── client.cc │ ├── client.hh │ ├── mail.cc │ ├── mail.hh │ └── sample │ │ ├── CMakeLists.txt │ │ └── msendmail.cc ├── spin-lock.hh ├── spin-lock.hxx ├── sqlite │ ├── CMakeLists.txt │ ├── sqlite.cc │ ├── sqlite.hh │ └── sqlite.hxx ├── stream │ ├── CMakeLists.txt │ ├── base16-decoder.cc │ ├── base16-decoder.hh │ ├── base16-encoder.cc │ ├── base16-encoder.hh │ ├── base64-decoder.cc │ ├── base64-decoder.hh │ ├── buffer.cc │ ├── buffer.hh │ ├── buffered-stream.cc │ ├── buffered-stream.hh │ ├── copy.cc │ ├── copy.hh │ ├── direct-fd-stream.cc │ ├── direct-fd-stream.hh │ ├── fd-stream.cc │ ├── fd-stream.hh │ ├── filter.cc │ ├── filter.hh │ ├── filter.hxx │ ├── hash.hh │ ├── html-escape.cc │ ├── html-escape.hh │ ├── limited-stream.cc │ ├── limited-stream.hh │ ├── lzma-decoder.cc │ ├── lzma-decoder.hh │ ├── lzma-encoder.cc │ ├── lzma-encoder.hh │ ├── lzma.cc │ ├── lzma.hh │ ├── net-fd-stream.cc │ ├── net-fd-stream.hh │ ├── percent-encoder.cc │ ├── percent-encoder.hh │ ├── stream.cc │ ├── stream.hh │ ├── string-stream.cc │ ├── string-stream.hh │ ├── tee-stream.cc │ ├── tee-stream.hh │ ├── tests │ │ ├── CMakeLists.txt │ │ ├── lzma-decoder.cc │ │ ├── lzma-encoder.cc │ │ ├── tst-filters.cc │ │ ├── tst-hash.cc │ │ └── tst-html-escape.cc │ ├── tls-stream.cc │ ├── tls-stream.hh │ ├── zlib-encoder.cc │ └── zlib-encoder.hh ├── string-ref.hh ├── string │ ├── CMakeLists.txt │ └── tests │ │ └── CMakeLists.txt ├── sync.doch ├── tests │ ├── CMakeLists.txt │ ├── tst-cache.cc │ ├── tst-container-of.cc │ ├── tst-intrusive-dlist.cc │ ├── tst-intrusive-hash-table.cc │ ├── tst-intrusive-slist.cc │ ├── tst-ref-countable.cc │ ├── tst-string-ref.cc │ └── tst-trie.cc ├── thread-pool.cc ├── thread-pool.hh ├── thread.cc ├── thread.hh ├── time.hh ├── tpl │ ├── CMakeLists.txt │ ├── abstract-value.cc │ ├── abstract-value.hh │ ├── append-helper.hh │ ├── ast │ │ ├── empty.cc │ │ ├── empty.hh │ │ ├── node.hh │ │ ├── repeated.cc │ │ ├── repeated.hh │ │ ├── root.cc │ │ ├── root.hh │ │ ├── text.cc │ │ ├── text.hh │ │ ├── var.cc │ │ └── var.hh │ ├── cache.cc │ ├── cache.hh │ ├── dict.cc │ ├── dict.hh │ ├── filter-factory.cc │ ├── filter-factory.hh │ ├── include.cc │ ├── include.hh │ ├── list.cc │ ├── list.hh │ ├── log.cc │ ├── log.hh │ ├── map.hh │ ├── parser.cc │ ├── parser.hh │ ├── template.cc │ ├── template.doch │ ├── template.hh │ ├── tests │ │ ├── CMakeLists.txt │ │ └── tst-tpl.cc │ ├── value.hh │ └── value.hxx ├── trie.hh ├── trie.hxx ├── unique-locker.hh ├── uptime.cc ├── uptime.hh ├── uri │ ├── CMakeLists.txt │ ├── normalize-path.cc │ ├── normalize-path.hh │ ├── parse-query.cc │ ├── parse-query.hh │ ├── percent-encoding.cc │ ├── percent-encoding.hh │ ├── scheme.hh │ ├── tests │ │ ├── CMakeLists.txt │ │ ├── tst-normalize-path.cc │ │ ├── tst-parse-query.cc │ │ ├── tst-percent-encoding.cc │ │ └── tst-url.cc │ ├── tools │ │ └── gen-percent-encoding-tables.cc │ ├── url.cc │ └── url.hh └── yield.hh └── tasks.org /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build-clang 3 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Alexandre Bique 2 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011-2012 Alexandre Bique 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /MIMOSA_VERSION: -------------------------------------------------------------------------------- 1 | 0.9.0 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ___ ___ __ ___ ___ ______ ________ __ 2 | |" \ /" | |" \ |" \ /" | / " \ /" ) /""\ 3 | \ \ // | || | \ \ // | // ____ \(: \___/ / \ 4 | /\\ \/. | |: | /\\ \/. | / / ) :)\___ \ /' /\ \ 5 | |: \. | |. | |: \. |(: (____/ // __/ \\ // __' \ 6 | |. \ /: | /\ |\ |. \ /: | \ / /" \ :)/ / \\ \ 7 | |___|\__/|___|(__\_|_)|___|\__/|___| \"_____/ (_______/(___/ \___) rt 8 | 9 | 소소 10 | 11 | Mimosa provides: 12 | - logging framework 13 | - options parser 14 | - intrusive containers 15 | - streams 16 | - rpc 17 | - http client and server 18 | - text template engine 19 | - bencode parser 20 | - and more ... :-) 21 | 22 | Depends 23 | - gcc >= 4.6 or clang >= 3.1 24 | - flex 25 | - bison 26 | - gnutls 27 | - zlib 28 | - lzma 29 | - bzip2 30 | - google protocol buffers 31 | -------------------------------------------------------------------------------- /cmake/Bison.cmake: -------------------------------------------------------------------------------- 1 | macro(mimosa_bison name) 2 | add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${name}.hh ${CMAKE_CURRENT_SOURCE_DIR}/${name}.cc 3 | COMMAND bison --output=${CMAKE_CURRENT_SOURCE_DIR}/${name}.cc 4 | ${CMAKE_CURRENT_SOURCE_DIR}/${name}.y 5 | DEPENDS ${name}.y 6 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 7 | endmacro(mimosa_bison) 8 | -------------------------------------------------------------------------------- /cmake/Flex.cmake: -------------------------------------------------------------------------------- 1 | macro(mimosa_flex name) 2 | add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${name}.hh ${CMAKE_CURRENT_SOURCE_DIR}/${name}.cc 3 | COMMAND flex --outfile=${CMAKE_CURRENT_SOURCE_DIR}/${name}.cc 4 | --header-file=${CMAKE_CURRENT_SOURCE_DIR}/${name}.hh 5 | ${CMAKE_CURRENT_SOURCE_DIR}/${name}.l 6 | DEPENDS ${name}.l 7 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 8 | endmacro(mimosa_flex) 9 | -------------------------------------------------------------------------------- /cmake/ProtocMimosa.cmake: -------------------------------------------------------------------------------- 1 | macro(mimosa_protoc name) 2 | add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${name}.pb.h ${CMAKE_CURRENT_SOURCE_DIR}/${name}.pb.cc 3 | COMMAND protoc --plugin=$ --mimosa_out=. ${name}.proto 4 | DEPENDS protoc-gen-mimosa ${name}.proto 5 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 6 | set_source_files_properties( 7 | ${CMAKE_CURRENT_SOURCE_DIR}/${name}.pb.h 8 | ${CMAKE_CURRENT_SOURCE_DIR}/${name}.pb.cc 9 | PROPERTIES GENERATED true) 10 | endmacro(mimosa_protoc) 11 | -------------------------------------------------------------------------------- /cmake/Tests.cmake: -------------------------------------------------------------------------------- 1 | add_custom_target(check) 2 | 3 | macro(mimosa_test MODULE) 4 | add_executable(tst-${MODULE} EXCLUDE_FROM_ALL ${ARGN}) 5 | target_link_libraries(tst-${MODULE} gtest_main gtest mimosa) 6 | add_custom_target(run-tst-${MODULE} ./tst-${MODULE} DEPENDS tst-${MODULE}) 7 | add_dependencies(check run-tst-${MODULE}) 8 | endmacro(mimosa_test) 9 | -------------------------------------------------------------------------------- /dist.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | VERSION=$($DISTDIR.tar.xz 25 | rm -rf $DISTDIR 26 | 27 | md5sum $DISTDIR.tar.xz >$DISTDIR.tar.xz.md5sum 28 | -------------------------------------------------------------------------------- /mimosa/archive/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive) 2 | 3 | add_library(mimosa-archive STATIC 4 | reader.cc 5 | writer.cc) 6 | 7 | install(FILES 8 | entry.hh 9 | reader.hh 10 | writer.hh 11 | DESTINATION include/mimosa/archive/) 12 | 13 | target_link_libraries(mimosa-archive PUBLIC mimosa PkgConfig::LibArchive) 14 | 15 | install(TARGETS mimosa-archive 16 | RUNTIME DESTINATION bin 17 | LIBRARY DESTINATION lib 18 | ARCHIVE DESTINATION lib) 19 | -------------------------------------------------------------------------------- /mimosa/bencode/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | copy.hh 3 | decoder.hh 4 | encoder.hh 5 | DESTINATION include/mimosa/bencode/) 6 | 7 | add_library(mimosa-bencode STATIC 8 | copy.cc 9 | decoder.cc 10 | encoder.cc 11 | ) 12 | target_link_libraries(mimosa-bencode PUBLIC mimosa) 13 | 14 | install(TARGETS mimosa-bencode 15 | RUNTIME DESTINATION bin 16 | LIBRARY DESTINATION lib 17 | ARCHIVE DESTINATION lib) 18 | -------------------------------------------------------------------------------- /mimosa/bencode/bencode.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @defgroup bencode bencode 4 | 5 | bencode is an encoding format used for bittorrent. 6 | See http://www.bittorrent.org/beps/bep_0003.html 7 | 8 | The connectivity is as follows: 9 | - Strings are length-prefixed base ten followed by a colon and the string. 10 | For example 4:spam corresponds to 'spam'. 11 | - Integers are represented by an 'i' followed by the number in base 10 12 | followed by an 'e'. For example i3e corresponds to 3 and i-3e corresponds 13 | to -3. Integers have no size limitation. i-0e is invalid. All encodings with 14 | a leading zero, such as i03e, are invalid, other than i0e, which of course 15 | corresponds to 0. 16 | - Lists are encoded as an 'l' followed by their elements (also bencoded) 17 | followed by an 'e'. For example l4:spam4:eggse corresponds to ['spam', 'eggs']. 18 | - Dictionaries are encoded as a 'd' followed by a list of alternating keys 19 | and their corresponding values followed by an 'e'. For example, 20 | d3:cow3:moo4:spam4:eggse corresponds to {'cow': 'moo', 'spam': 'eggs'} and 21 | d4:spaml1:a1:bee corresponds to {'spam': ['a', 'b']}. Keys must be strings 22 | and appear in sorted order (sorted as raw strings, not alphanumerics). 23 | 24 | */ 25 | 26 | namespace mimosa 27 | { 28 | /** @ingroup bencode */ 29 | namespace bencode {} 30 | } 31 | -------------------------------------------------------------------------------- /mimosa/bencode/copy.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "decoder.hh" 4 | # include "encoder.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace bencode 9 | { 10 | /** 11 | * @ingroup bencode 12 | * 13 | * @brief copy a value from dec to enc 14 | * @return true if copy succeed, false otherwise 15 | */ 16 | bool copyValue(Decoder & dec, 17 | Encoder & enc); 18 | 19 | /** 20 | * @ingroup bencode 21 | * 22 | * @brief copy the current token to enc 23 | * @return true on success, false otherwise 24 | */ 25 | bool copyToken(Token token, 26 | const Decoder & dec, 27 | Encoder & enc); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/bencode/decoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../string-ref.hh" 4 | # include "../stream/stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace bencode 9 | { 10 | /** 11 | * @ingroup bencode 12 | */ 13 | enum Token 14 | { 15 | /* real token */ 16 | kInt, 17 | kData, 18 | kList, 19 | kDict, 20 | kEnd, 21 | kEof, 22 | 23 | /* error token */ 24 | kReadError, 25 | kParseError, 26 | }; 27 | 28 | /** 29 | * @ingroup bencode 30 | */ 31 | class Decoder 32 | { 33 | public: 34 | explicit Decoder(stream::Stream::Ptr input); 35 | 36 | Token pull(); 37 | bool eatValue(); 38 | 39 | inline int64_t getInt() const { return int_; } 40 | inline const std::string & getData() const { return data_; } 41 | 42 | inline void setInput(stream::Stream::Ptr input) { input_ = input; } 43 | 44 | private: 45 | Token pullInt(); 46 | Token pullData(); 47 | 48 | stream::Stream::Ptr input_; 49 | std::string data_; 50 | int64_t int_; 51 | }; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /mimosa/bencode/encoder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "encoder.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace bencode 10 | { 11 | Encoder::Encoder(stream::Stream::Ptr output) 12 | : output_(std::move(std::move(output))) 13 | { 14 | } 15 | 16 | bool 17 | Encoder::pushInt(int64_t value) 18 | { 19 | char buffer[64]; 20 | size_t len; 21 | 22 | len = snprintf(buffer, sizeof (buffer), "i%lde", value); 23 | return output_->loopWrite(buffer, len) == (int)len; 24 | } 25 | 26 | bool 27 | Encoder::pushData(const char *data, size_t data_len) 28 | { 29 | char buffer[64]; 30 | size_t len; 31 | 32 | len = snprintf(buffer, sizeof (buffer), "%zu:", data_len); 33 | return output_->loopWrite(buffer, len) == (int)len && 34 | output_->loopWrite(data, data_len) == (int)data_len; 35 | } 36 | 37 | bool 38 | Encoder::startDict() 39 | { 40 | return output_->loopWrite("d", 1) == 1; 41 | } 42 | 43 | bool 44 | Encoder::startList() 45 | { 46 | return output_->loopWrite("l", 1) == 1; 47 | } 48 | 49 | bool 50 | Encoder::end() 51 | { 52 | return output_->loopWrite("e", 1) == 1; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /mimosa/bencode/encoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../string-ref.hh" 4 | # include "../stream/stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace bencode 9 | { 10 | /** 11 | * @ingroup bencode 12 | */ 13 | class Encoder 14 | { 15 | public: 16 | explicit Encoder(stream::Stream::Ptr output); 17 | 18 | bool pushInt(int64_t value); 19 | bool pushData(const char *data, size_t len); 20 | 21 | inline bool pushData(const std::string & data) { 22 | return pushData(data.data(), data.size()); 23 | } 24 | 25 | inline bool pushData(const StringRef & data) { 26 | return pushData(data.data(), data.size()); 27 | } 28 | 29 | bool startDict(); 30 | bool startList(); 31 | bool end(); 32 | 33 | private: 34 | stream::Stream::Ptr output_; 35 | }; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /mimosa/bittorrent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | torrent-descriptor.hh 3 | torrent-parser.hh 4 | DESTINATION include/mimosa/bittorrent/) 5 | 6 | add_library(mimosa-bittorrent STATIC 7 | torrent-descriptor.cc 8 | torrent-descriptor.hh 9 | torrent-parser.cc 10 | torrent-parser.hh 11 | ) 12 | target_link_libraries(mimosa-bittorrent PUBLIC 13 | mimosa-bencode 14 | mimosa) 15 | 16 | install(TARGETS mimosa-bittorrent 17 | RUNTIME DESTINATION bin 18 | LIBRARY DESTINATION lib 19 | ARCHIVE DESTINATION lib) 20 | -------------------------------------------------------------------------------- /mimosa/bittorrent/torrent-descriptor.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace mimosa { namespace bittorrent { 9 | struct TorrentDescriptor { 10 | TorrentDescriptor(); 11 | 12 | struct File { 13 | std::string path_; 14 | uint64_t length_; 15 | }; 16 | 17 | struct Tracker { 18 | std::string url_; 19 | bool is_backup_; 20 | }; 21 | 22 | struct Node { 23 | std::string host_; 24 | uint16_t port_; 25 | }; 26 | 27 | struct Sha1 { 28 | uint8_t bytes_[20]; 29 | }; 30 | 31 | struct Sha2 { 32 | uint8_t bytes_[32]; 33 | }; 34 | 35 | std::string name_; 36 | std::string creation_date_; 37 | uint64_t length_; 38 | uint64_t piece_length_; 39 | bool is_private_; 40 | std::vector files_; 41 | std::vector trackers_; 42 | std::vector nodes_; 43 | Sha1 info_hash_v1_; 44 | Sha2 info_hash_v2_; 45 | std::vector pieces_; 46 | 47 | void dump(std::ostream &stream); 48 | }; 49 | }} // namespace mimosa::bittorrent 50 | -------------------------------------------------------------------------------- /mimosa/compat/uio.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) 7 | # include 8 | #else 9 | # define IOV_MAX 128 10 | struct iovec { 11 | void *iov_base = nullptr; 12 | uint64_t iov_len = 0; 13 | }; 14 | #endif 15 | -------------------------------------------------------------------------------- /mimosa/container-of.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | /** 8 | * Returns the address of the object of type T containing the given member at the address u. 9 | */ 10 | template 11 | T * 12 | containerOf(U * u, U T::*Member) noexcept 13 | { 14 | union { 15 | T * obj; 16 | uint8_t * obj2; 17 | }; 18 | union { 19 | U * mb; 20 | uint8_t * mb2; 21 | }; 22 | 23 | obj = nullptr; 24 | mb = &(obj->*Member); 25 | auto offset = mb2 - obj2; 26 | mb = u; 27 | obj2 = mb2 - offset; 28 | return obj; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mimosa/cpu-count.cc: -------------------------------------------------------------------------------- 1 | #if __WIN32__ 2 | # include 3 | #endif 4 | 5 | #include 6 | 7 | #include "cpu-count.hh" 8 | 9 | namespace mimosa 10 | { 11 | size_t cpuCount() noexcept 12 | { 13 | #ifdef __WIN32__ 14 | SYSTEM_INFO info; 15 | GetSystemInfo(&info); 16 | return info.dwNumberOfProcessors; 17 | #else 18 | return static_cast(sysconf(_SC_NPROCESSORS_ONLN)); 19 | #endif 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mimosa/cpu-count.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | /** 8 | * @return the number of available CPU 9 | */ 10 | size_t cpuCount() noexcept; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /mimosa/cpu-foreach.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | /** 8 | * Will create one thread for each cpu, set the cpu affinity 9 | * and execute cb. 10 | * 11 | * Thread created in cb will by default keep the same cpu affinity. 12 | */ 13 | template 14 | void cpuForeach(const Callback& cb, bool affinity = false, size_t ratio = 1); 15 | } 16 | 17 | #include "cpu-foreach.hxx" -------------------------------------------------------------------------------- /mimosa/cpu-foreach.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Required for CPU_ALLOC(), ... */ 4 | #ifndef _GNU_SOURCE 5 | # define _GNU_SOURCE 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "cpu-count.hh" 16 | #include "cpu-foreach.hh" 17 | #include "thread.hh" 18 | 19 | namespace mimosa 20 | { 21 | template 22 | void cpuForeach(const Callback& cb, bool affinity, size_t ratio) 23 | { 24 | assert(ratio >= 1); 25 | 26 | std::vector threads; 27 | size_t nproc = cpuCount(); 28 | threads.resize(nproc * ratio); 29 | 30 | for (size_t i = 0; i < nproc * ratio; ++i) 31 | { 32 | threads[i].start([i, nproc, &cb, affinity, ratio] { 33 | #ifdef HAS_SCHED_SETAFFINITY 34 | cpu_set_t * set = nullptr; 35 | if (affinity) 36 | { 37 | set = CPU_ALLOC(nproc); 38 | assert(set); 39 | CPU_ZERO_S(nproc, set); 40 | CPU_SET(i / ratio, set); 41 | 42 | sched_setaffinity(0, CPU_ALLOC_SIZE(nproc), set); 43 | } 44 | #endif /* HAS_SCHED_SETAFFINITY */ 45 | 46 | try { 47 | cb(); 48 | } catch (...) { 49 | } 50 | #ifdef HAS_SCHED_SETAFFINITY 51 | if (affinity) 52 | CPU_FREE(set); 53 | #endif 54 | }); 55 | } 56 | 57 | for (size_t i = 0; i < nproc * ratio; ++i) 58 | threads[i].join(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mimosa/endian.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # ifdef __FreeBSD__ 4 | # include 5 | # elif defined(__MACH__) 6 | # include 7 | 8 | # define htobe16(x) OSSwapHostToBigInt16(x) 9 | # define htole16(x) OSSwapHostToLittleInt16(x) 10 | # define be16toh(x) OSSwapBigToHostInt16(x) 11 | # define le16toh(x) OSSwapLittleToHostInt16(x) 12 | 13 | # define htobe32(x) OSSwapHostToBigInt32(x) 14 | # define htole32(x) OSSwapHostToLittleInt32(x) 15 | # define be32toh(x) OSSwapBigToHostInt32(x) 16 | # define le32toh(x) OSSwapLittleToHostInt32(x) 17 | 18 | # define htobe64(x) OSSwapHostToBigInt64(x) 19 | # define htole64(x) OSSwapHostToLittleInt64(x) 20 | # define be64toh(x) OSSwapBigToHostInt64(x) 21 | # define le64toh(x) OSSwapLittleToHostInt64(x) 22 | 23 | # else 24 | # include 25 | # endif 26 | 27 | -------------------------------------------------------------------------------- /mimosa/env.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "env.hh" 4 | 5 | namespace mimosa 6 | { 7 | void setenv(const std::string &key, const std::string &value) 8 | { 9 | #if defined(__unix__) || defined(__APPLE__) 10 | ::setenv(key.c_str(), value.c_str(), true); 11 | #elif defined(__WIN32__) 12 | _putenv_s(key.c_str(), value.c_str()); 13 | #endif 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mimosa/env.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | void setenv(const std::string &key, const std::string &value); 8 | } 9 | -------------------------------------------------------------------------------- /mimosa/fft/fft.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa { 4 | namespace fft { 5 | 6 | template 7 | void fft(const fp_type *signal, fp_type *spectrum); 8 | 9 | template 10 | void ifft(const fp_type *spectrum, fp_type *signal); 11 | 12 | } 13 | } 14 | 15 | #include "fft.hxx" 16 | -------------------------------------------------------------------------------- /mimosa/fft/fft.hxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace mimosa { 5 | namespace fft { 6 | 7 | template 8 | void fft(const fp_type *signal, fp_type *spectrum) 9 | { 10 | static_assert(len & (len - 1) == 0, "len is a power of 2"); 11 | 12 | for (int i = 0; i < len; i += 2) 13 | { 14 | spectrum[i] = 0; 15 | spectrum[i + 1] = 0; 16 | for (int j = 0; j < len; ++j) 17 | { 18 | const fp_type angle = 2 * M_PI * j / len; 19 | spectrum[i] += signal[j] * std::cos(angle); 20 | spectrum[i + 1] += signal[j] * std::sin(angle); 21 | } 22 | } 23 | } 24 | 25 | template 26 | void ifft(const fp_type *spectrum, fp_type *signal) 27 | { 28 | static_assert(len & (len - 1) == 0, "len is a power of 2"); 29 | 30 | for (int i = 0; i < len; ++i) 31 | { 32 | signal[i] = 0; 33 | for (int j = 0; j < len; j += 2) 34 | { 35 | const fp_type angle = 2 * M_PI * j / len; 36 | signal[i] += spectrum[j] * std::cos(angle) + spectrum[j + 1] + std::sin(angle); 37 | } 38 | } 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mimosa/fft/normalize.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa { 4 | namespace fft { 5 | 6 | template 7 | void normalizeEuclide(fp_type *spectrum); 8 | 9 | } 10 | } 11 | 12 | #include "normalize.hxx" 13 | -------------------------------------------------------------------------------- /mimosa/fft/normalize.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "normalize.hh" 6 | 7 | namespace mimosa { 8 | namespace fft { 9 | 10 | template 11 | void normalizeEuclide(fp_type *spectrum) 12 | { 13 | fp_type norm = 0; 14 | 15 | for (int i = 0; i < len; ++i) 16 | norm += spectrum[i] * spectrum[i]; 17 | norm = std::sqrt(norm); 18 | 19 | for (int i = 0; i < len; ++i) 20 | spectrum[i] /= norm; 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mimosa/fft/scwf-gen.cc: -------------------------------------------------------------------------------- 1 | #include "scwf-gen.hh" 2 | 3 | int main(int argc, char **argv) 4 | { 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /mimosa/fft/scwf-gen.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fft.hh" 4 | 5 | template 6 | void generateIdealSawSpectrum(fp_type *spectrum); 7 | 8 | template 9 | void generateIdealSawSignal(fp_type *signal); 10 | 11 | template 12 | void generateIdealSquareSpectrum(fp_type *spectrum); 13 | 14 | template 15 | void generateIdealSquareSignal(fp_type *signal); 16 | 17 | #include "scwf-gen.hxx" 18 | -------------------------------------------------------------------------------- /mimosa/flat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | flat.hh 3 | DESTINATION include/mimosa/flat/) 4 | 5 | add_library(mimosa-flat STATIC flat.cc) 6 | target_link_libraries(mimosa-flat PUBLIC mimosa) 7 | 8 | install(TARGETS mimosa-flat 9 | RUNTIME DESTINATION bin 10 | LIBRARY DESTINATION lib 11 | ARCHIVE DESTINATION lib) 12 | -------------------------------------------------------------------------------- /mimosa/format/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | print.hh 3 | print.hxx 4 | format.hh 5 | format.hxx 6 | format.doch 7 | format-stream.hh 8 | DESTINATION include/mimosa/format/) 9 | 10 | add_subdirectory(tests) 11 | -------------------------------------------------------------------------------- /mimosa/format/format-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "format.hh" 4 | # include "../stream/stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace format 9 | { 10 | // XXX take a reference to stream, not a refcounted pointer 11 | template 12 | inline 13 | bool format(stream::Stream & stream, 14 | const char * fmt, 15 | Args ... args) 16 | { 17 | std::string str(format::str(fmt, args...)); 18 | if (str.empty()) 19 | return true; 20 | int64_t bytes = stream.loopWrite(str.data(), str.size()); 21 | return static_cast (bytes) == str.size(); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/format/format.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @page Format 4 | 5 | The format namespace contains an alternative to std::ostream. 6 | For exemple you can do: 7 | @code 8 | mimosa::format::format("Hello %v!\n", some_object); 9 | mimosa::format::format("Hello %v, this is your age %d or 0x%x!\n", some_object, 24, 24); 10 | @endcode 11 | 12 | @section Formatting Supported formatting 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
%vthe default operator<<(std::ostream&, const T &)
%dprint integer with decimal format
%oprint integer with octal format
%xprint integer with hexadecimal format (lowercase)
%Xprint integer with hexadecimal format (uppercase)
%pprint pointers with hexadecimal format (lowercase)
%Pprint pointers with hexadecimal format (uppercase)
%%print the `%' character
24 | 25 | */ 26 | -------------------------------------------------------------------------------- /mimosa/format/format.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa { namespace format { 6 | inline std::ostream &format(std::ostream &os, const char *fmt); 7 | 8 | template 9 | inline std::ostream &format(std::ostream &os, const char *fmt, const T &value, Args... args); 10 | 11 | template 12 | inline std::string str(const char *fmt, Args... args) { 13 | std::ostringstream os; 14 | format(os, fmt, args...); 15 | return os.str(); 16 | } 17 | }} // namespace mimosa::format 18 | 19 | #include "format.hxx" 20 | -------------------------------------------------------------------------------- /mimosa/format/print.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "../time.hh" 7 | # include "../stream/stream.hh" 8 | # include "../string-ref.hh" 9 | 10 | namespace mimosa 11 | { 12 | namespace format 13 | { 14 | template 15 | inline bool printDecimal(stream::Stream & stream, T value); 16 | 17 | bool printHex(stream::Stream & stream, uint64_t value); 18 | /** will print the size with a precision of 3 digits */ 19 | bool printByteSize(stream::Stream & stream, uint64_t value); 20 | 21 | bool printDuration(stream::Stream & stream, Time time); 22 | 23 | template 24 | inline bool printStatic(stream::Stream & stream, const char (&str)[len]); 25 | inline bool print(stream::Stream & stream, const char *str, size_t len); 26 | inline bool print(stream::Stream & stream, const char *str); 27 | inline bool print(stream::Stream & stream, const std::string & str); 28 | inline bool print(stream::Stream & stream, const StringRef & str); 29 | } 30 | } 31 | 32 | # include "print.hxx" 33 | 34 | -------------------------------------------------------------------------------- /mimosa/format/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa-format tst-format.cc tst-print.cc) 2 | -------------------------------------------------------------------------------- /mimosa/format/tests/tst-format.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../format.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace format 8 | { 9 | namespace 10 | { 11 | TEST(Format, Simple) 12 | { 13 | EXPECT_EQ("1", str("1")); 14 | EXPECT_EQ("42", str("%v", 42)); 15 | EXPECT_EQ("42", str("%", 42)); 16 | EXPECT_EQ("42", str("%d", 42)); 17 | EXPECT_EQ("2a", str("%x", 42)); 18 | EXPECT_EQ("2a", str("%x", 42)); 19 | EXPECT_EQ("%", str("%%", 42)); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mimosa/format/tests/tst-print.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../print.hh" 4 | #include "../../stream/string-stream.hh" 5 | 6 | #define CHECK_BYTE_SIZE(Size, Ref) \ 7 | do { \ 8 | stream::StringStream s; \ 9 | printByteSize(s, Size); \ 10 | EXPECT_EQ(Ref, s.str()); \ 11 | } while (0) 12 | 13 | namespace mimosa 14 | { 15 | namespace format 16 | { 17 | namespace tests 18 | { 19 | TEST(Print, ByteSize) 20 | { 21 | CHECK_BYTE_SIZE(0, "0B"); 22 | 23 | CHECK_BYTE_SIZE(1ull << 0, "1B"); 24 | CHECK_BYTE_SIZE(1ull << 10, "1KiB"); 25 | CHECK_BYTE_SIZE(1ull << 20, "1MiB"); 26 | CHECK_BYTE_SIZE(1ull << 30, "1GiB"); 27 | CHECK_BYTE_SIZE(1ull << 40, "1TiB"); 28 | CHECK_BYTE_SIZE(1ull << 50, "1PiB"); 29 | CHECK_BYTE_SIZE(1ull << 60, "1EiB"); 30 | 31 | CHECK_BYTE_SIZE(1023, "1023B"); 32 | 33 | CHECK_BYTE_SIZE(2*1024, "2KiB"); 34 | CHECK_BYTE_SIZE(2*1024 + 512, "2.5KiB"); 35 | CHECK_BYTE_SIZE(2*1024 + 512 + 256, "2.75KiB"); 36 | CHECK_BYTE_SIZE(20*1024 + 512 + 256, "20.7KiB"); 37 | CHECK_BYTE_SIZE(200*1024 + 512 + 256, "200KiB"); 38 | CHECK_BYTE_SIZE(2*1024*1024 + 512, "2MiB"); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mimosa/fs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | copy.hh 3 | dir-iterator.hh 4 | exists.hh 5 | find.hh 6 | move.hh 7 | rm.hh 8 | DESTINATION include/mimosa/fs/) 9 | 10 | add_library(mimosa-fs STATIC 11 | copy.cc 12 | dir-iterator.cc 13 | exists.cc 14 | find.cc 15 | move.cc 16 | rm.cc 17 | ) 18 | 19 | install(TARGETS mimosa-fs 20 | RUNTIME DESTINATION bin 21 | LIBRARY DESTINATION lib 22 | ARCHIVE DESTINATION lib) 23 | -------------------------------------------------------------------------------- /mimosa/fs/copy.cc: -------------------------------------------------------------------------------- 1 | #include "copy.hh" 2 | 3 | #include "../stream/copy.hh" 4 | #include "../stream/direct-fd-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace fs 9 | { 10 | bool copyFile(const std::string &src, const std::string &dst) 11 | { 12 | stream::DirectFdStream srcStream; 13 | 14 | struct ::stat st; 15 | 16 | if (::stat(src.c_str(), &st)) 17 | return false; 18 | 19 | if (!srcStream.open(src.c_str(), O_RDONLY)) 20 | return false; 21 | 22 | stream::DirectFdStream dstStream; 23 | if (!dstStream.open(dst.c_str(), O_CREAT | O_TRUNC | O_WRONLY)) 24 | return false; 25 | 26 | if (st.st_size != stream::copy(srcStream, dstStream)) { 27 | ::unlink(dst.c_str()); 28 | return false; 29 | } 30 | 31 | return true; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mimosa/fs/copy.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | namespace fs 8 | { 9 | bool copyFile(const std::string &src, 10 | const std::string &dst); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mimosa/fs/dir-iterator.cc: -------------------------------------------------------------------------------- 1 | #include "dir-iterator.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace fs 6 | { 7 | DirIterator::DirIterator(const std::string & path) 8 | : dir_(::opendir(path.c_str())), 9 | path_(path), 10 | entry_(nullptr) 11 | { 12 | ++*this; 13 | } 14 | 15 | DirIterator::~DirIterator() 16 | { 17 | if (dir_) 18 | ::closedir(dir_); 19 | } 20 | 21 | DirIterator& 22 | DirIterator::operator++() 23 | { 24 | if (dir_) 25 | entry_ = ::readdir(dir_); 26 | 27 | if (entry_ && entry_->d_name[0] == '.' && 28 | (entry_->d_name[1] == '\0' || 29 | (entry_->d_name[1] == '.' && entry_->d_name[2] == '\0'))) 30 | return ++*this; 31 | return *this; 32 | } 33 | 34 | std::string 35 | DirIterator::entryPath() const 36 | { 37 | std::string entry_path(path_); 38 | 39 | if (*entry_path.rbegin() != '/') 40 | entry_path.append("/"); 41 | entry_path.append(entry_->d_name); 42 | return entry_path; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mimosa/fs/dir-iterator.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include 7 | 8 | namespace mimosa 9 | { 10 | namespace fs 11 | { 12 | /** 13 | * @ingroup Fs 14 | */ 15 | class DirIterator 16 | { 17 | public: 18 | explicit DirIterator(const std::string & path); 19 | ~DirIterator(); 20 | 21 | inline bool ok() const { return dir_; } 22 | inline bool end() const { return !entry_; } 23 | 24 | inline const std::string & dirPath() const { return path_; } 25 | std::string entryPath() const; 26 | inline const char * entryName() const { return entry_->d_name; } 27 | 28 | DirIterator& operator++(); 29 | 30 | private: 31 | ::DIR * dir_; 32 | std::string path_; 33 | ::dirent * entry_; 34 | }; 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /mimosa/fs/exists.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "exists.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace fs 10 | { 11 | bool exists(const std::string &path) 12 | { 13 | struct ::stat st; 14 | return ::stat(path.c_str(), &st) == 0; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mimosa/fs/exists.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | namespace fs 8 | { 9 | bool exists(const std::string &path); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /mimosa/fs/find.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "find.hh" 6 | #include "dir-iterator.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace fs 11 | { 12 | void 13 | find(const std::string & root, 14 | uint32_t max_depth, 15 | const std::function & cb) 16 | { 17 | DirIterator it(root); 18 | 19 | if (!it.ok()) 20 | return; 21 | 22 | for (; !it.end(); ++it) 23 | { 24 | std::string path = it.entryPath(); 25 | cb(path); 26 | 27 | if (max_depth == 0) 28 | continue; 29 | 30 | struct stat st; 31 | if (::stat(path.c_str(), &st)) 32 | continue; 33 | 34 | if (S_ISDIR(st.st_mode)) 35 | find(path, max_depth - 1, cb); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mimosa/fs/find.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | # include 6 | 7 | namespace mimosa 8 | { 9 | namespace fs 10 | { 11 | /** 12 | * @ingroup Fs 13 | * @param cb return false to break the loop 14 | * @param max_depth the maximum depth 15 | */ 16 | void 17 | find(const std::string & root, 18 | uint32_t max_depth, 19 | const std::function &cb); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /mimosa/fs/fs.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @defgroup Fs File system 4 | 5 | This module regroups file system related helpers. 6 | 7 | */ 8 | 9 | namespace mimosa 10 | { 11 | /** @ingroup Fs */ 12 | namespace fs {} 13 | } 14 | -------------------------------------------------------------------------------- /mimosa/fs/move.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "move.hh" 5 | #include "copy.hh" 6 | #include "rm.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace fs 11 | { 12 | bool moveFile(const std::string &src, 13 | const std::string &dst) 14 | { 15 | if (!::rename(src.c_str(), dst.c_str())) 16 | return true; 17 | 18 | if (errno == EXDEV) 19 | { 20 | if (!copyFile(src, dst)) 21 | return false; 22 | if (!rm(src, false, true)) { 23 | rm(dst, false, true); 24 | return false; 25 | } 26 | return true; 27 | } 28 | return false; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mimosa/fs/move.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | namespace fs 8 | { 9 | bool moveFile(const std::string &src, 10 | const std::string &dst); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mimosa/fs/rm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "dir-iterator.hh" 7 | #include "rm.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace fs 12 | { 13 | bool 14 | rm(const std::string & path, bool recursive, bool force) 15 | { 16 | struct ::stat st; 17 | 18 | if (::stat(path.c_str(), &st)) 19 | return false || force; 20 | 21 | if (S_ISREG(st.st_mode) || 22 | S_ISFIFO(st.st_mode) || 23 | #ifndef __WIN32__ 24 | S_ISSOCK(st.st_mode) || 25 | S_ISLNK(st.st_mode) || 26 | #endif 27 | S_ISBLK(st.st_mode) || 28 | S_ISCHR(st.st_mode)) { 29 | if (!::unlink(path.c_str())) 30 | return true; 31 | if (!force || errno != EPERM) 32 | return false; 33 | if (::chmod(path.c_str(), 0700)) 34 | return false; 35 | return !::unlink(path.c_str()); 36 | } 37 | 38 | if (S_ISDIR(st.st_mode)) { 39 | if (recursive) 40 | for (DirIterator it(path); !it.end(); ++it) 41 | rm(it.entryPath(), true, force); 42 | if (!::rmdir(path.c_str())) 43 | return true; 44 | if (!force || errno != EPERM) 45 | return false; 46 | if (::chmod(path.c_str(), 0700)) 47 | return false; 48 | return !::rmdir(path.c_str()); 49 | } 50 | 51 | return false; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mimosa/fs/rm.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace fs 8 | { 9 | bool rm(const std::string & path, 10 | bool recursive = false, 11 | bool force = false); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /mimosa/function.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "ref-countable.hh" 6 | # include "non-copyable.hh" 7 | 8 | namespace mimosa 9 | { 10 | template 11 | class Function : public std::function, 12 | public RefCountable >, 13 | private NonCopyable 14 | { 15 | public: 16 | inline Function(std::function && fct) 17 | : std::function(fct) 18 | { 19 | } 20 | 21 | inline Function() {} 22 | }; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /mimosa/future.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "ref-countable.hh" 4 | # include "condition.hh" 5 | # include "mutex.hh" 6 | 7 | namespace mimosa 8 | { 9 | /** 10 | * @ingroup Sync 11 | */ 12 | template 13 | class Future : public RefCountable > 14 | { 15 | public: 16 | 17 | enum State 18 | { 19 | kUnset, 20 | kSet, 21 | kCanceled, 22 | }; 23 | 24 | inline Future(const T & value = T(), State state = kUnset); 25 | 26 | inline bool isReady() const; 27 | inline bool isCanceled() const; 28 | inline State state() const; 29 | inline void wait(); 30 | inline bool timedWait(Time time); 31 | inline T & get(); 32 | inline void set(const T & t); 33 | inline void cancel(); 34 | 35 | private: 36 | T value_; 37 | State state_; 38 | Mutex lock_; 39 | Condition cond_; 40 | }; 41 | } 42 | 43 | # include "future.hxx" 44 | 45 | -------------------------------------------------------------------------------- /mimosa/git/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | archive.hh 3 | blob.hh 4 | commit.hh 5 | diff.hh 6 | patch.hh 7 | reference.hh 8 | repository.hh 9 | revwalk.hh 10 | tag.hh 11 | tree-entry.hh 12 | tree.hh 13 | DESTINATION include/mimosa/git/) 14 | 15 | add_library(mimosa-git STATIC 16 | archive.cc 17 | reference.cc 18 | repository.cc 19 | revwalk.cc 20 | tree.cc 21 | ) 22 | 23 | target_link_libraries(mimosa-git PUBLIC 24 | mimosa-archive 25 | mimosa) 26 | 27 | install(TARGETS mimosa-git 28 | RUNTIME DESTINATION bin 29 | LIBRARY DESTINATION lib 30 | ARCHIVE DESTINATION lib) 31 | -------------------------------------------------------------------------------- /mimosa/git/archive.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../archive/writer.hh" 4 | # include "tree.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace git 9 | { 10 | bool gitArchive(Tree & tree, 11 | mimosa::archive::Writer & archive, 12 | const std::string & prefix = ""); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /mimosa/git/blob.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace git 8 | { 9 | class Blob 10 | { 11 | public: 12 | inline explicit Blob(git_blob * blob = nullptr) : blob_(blob) {} 13 | inline ~Blob() { git_blob_free(blob_); } 14 | 15 | inline operator git_blob *() { return blob_; } 16 | inline git_blob ** ref() { return &blob_; } 17 | 18 | private: 19 | git_blob * blob_; 20 | }; 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /mimosa/git/commit.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../mimosa/mimosa/non-copyable.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace git 10 | { 11 | class Commit : public NonCopyable 12 | { 13 | public: 14 | inline Commit() : commit_(nullptr) {} 15 | inline Commit(git_repository *repo, const git_oid *id) { 16 | git_commit_lookup(&commit_, repo, id); 17 | } 18 | inline ~Commit() { git_commit_free(commit_); } 19 | 20 | inline git_commit** ref() { return &commit_; } 21 | inline operator git_commit *() const { return commit_; } 22 | 23 | private: 24 | git_commit *commit_; 25 | }; 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /mimosa/git/diff.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace git 8 | { 9 | class Diff 10 | { 11 | public: 12 | inline explicit Diff(git_diff * diff = nullptr) : diff_(diff) {} 13 | inline ~Diff() { git_diff_free(diff_); } 14 | 15 | inline operator git_diff *() { return diff_; } 16 | inline git_diff ** ref() { return &diff_; } 17 | 18 | private: 19 | git_diff * diff_; 20 | }; 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /mimosa/git/patch.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace git 6 | { 7 | class Patch 8 | { 9 | public: 10 | inline explicit Patch(git_patch * patch = nullptr) : patch_(patch) {} 11 | inline ~Patch() { git_patch_free(patch_); } 12 | 13 | inline operator git_patch *() { return patch_; } 14 | inline git_patch ** ref() { return &patch_; } 15 | 16 | private: 17 | git_patch * patch_; 18 | }; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /mimosa/git/reference.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "reference.hh" 4 | #include "tag.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace git 9 | { 10 | bool referenceToOid(const Repository & repo, 11 | const std::string & ref, 12 | git_oid * oid) 13 | { 14 | if (!git_oid_fromstrp(oid, ref.c_str())) 15 | return true; 16 | if (!git_reference_name_to_id(oid, repo, ref.c_str())) 17 | return true; 18 | 19 | Reference r; 20 | if (!git_reference_dwim(r.ref(), repo, ref.c_str())) { 21 | const git_oid *target = git_reference_target(r); 22 | if (target) { 23 | memcpy(oid, target, sizeof (*target)); 24 | return true; 25 | } 26 | } 27 | 28 | return false; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mimosa/git/reference.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../non-copyable.hh" 6 | # include "repository.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace git 11 | { 12 | class Reference : private NonCopyable 13 | { 14 | public: 15 | inline Reference() : ref_(nullptr) {} 16 | inline ~Reference() { git_reference_free(ref_); } 17 | 18 | inline operator git_reference *() { return ref_; } 19 | inline git_reference ** ref() { return &ref_; } 20 | 21 | private: 22 | git_reference * ref_; 23 | }; 24 | 25 | bool referenceToOid(const Repository & repo, 26 | const std::string & ref, 27 | git_oid * oid); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/git/repository.cc: -------------------------------------------------------------------------------- 1 | #include "repository.hh" 2 | #include "commit.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace git 7 | { 8 | Repository::Repository(const std::string & repo_path) 9 | : repo_(nullptr) 10 | { 11 | git_repository_open(&repo_, repo_path.c_str()); 12 | } 13 | 14 | Repository::~Repository() 15 | { 16 | git_repository_free(repo_); 17 | } 18 | 19 | int64_t 20 | Repository::lastCommitTime() const 21 | { 22 | git_oid oid; 23 | if (git_reference_name_to_id(&oid, repo_, "HEAD")) 24 | return 0; 25 | 26 | Commit commit(repo_, &oid); 27 | return static_cast(git_commit_time(commit)) * 1000 28 | + git_commit_time_offset(commit); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mimosa/git/repository.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include 7 | 8 | namespace mimosa 9 | { 10 | namespace git 11 | { 12 | class Repository 13 | { 14 | public: 15 | explicit Repository(const std::string & repo_path); 16 | ~Repository(); 17 | 18 | inline operator git_repository * () const { return repo_; } 19 | 20 | int64_t lastCommitTime() const; 21 | 22 | private: 23 | git_repository *repo_; 24 | }; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mimosa/git/revwalk.cc: -------------------------------------------------------------------------------- 1 | #include "revwalk.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace git 6 | { 7 | Revwalk::Revwalk(git_repository * repo) 8 | : walk_(nullptr) 9 | { 10 | git_revwalk_new(&walk_, repo); 11 | } 12 | 13 | Revwalk::~Revwalk() 14 | { 15 | git_revwalk_free(walk_); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mimosa/git/revwalk.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace git 8 | { 9 | class Revwalk 10 | { 11 | public: 12 | explicit Revwalk(git_repository *repo); 13 | ~Revwalk(); 14 | 15 | inline operator git_revwalk *() { return walk_; } 16 | 17 | private: 18 | git_revwalk *walk_; 19 | }; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /mimosa/git/tag.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../non-copyable.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace git 10 | { 11 | class Tag : public NonCopyable 12 | { 13 | public: 14 | inline Tag() : tag_(nullptr) {} 15 | inline ~Tag() { git_tag_free(tag_); } 16 | 17 | inline operator git_tag *() const { return tag_; } 18 | inline git_tag ** ref() { return &tag_; } 19 | 20 | private: 21 | git_tag * tag_; 22 | }; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/git/tree-entry.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace git 6 | { 7 | class TreeEntry 8 | { 9 | public: 10 | inline explicit TreeEntry(git_tree_entry * entry = nullptr) : entry_(entry) {} 11 | inline ~TreeEntry() { git_tree_entry_free(entry_); } 12 | 13 | inline operator git_tree_entry *() { return entry_; } 14 | inline git_tree_entry ** ref() { return &entry_; } 15 | 16 | private: 17 | git_tree_entry * entry_; 18 | }; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /mimosa/git/tree.cc: -------------------------------------------------------------------------------- 1 | #include "tree.hh" 2 | #include "tree-entry.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace git 7 | { 8 | Tree::Tree(git_repository * repo, 9 | const git_oid * id) 10 | : tree_(nullptr) 11 | { 12 | if (id) 13 | git_tree_lookup(&tree_, repo, id); 14 | } 15 | 16 | Tree::Tree(git_repository * repo, 17 | const git_oid * id, 18 | const std::string & directory) 19 | : tree_(nullptr) 20 | { 21 | if (directory.empty()) { 22 | git_tree_lookup(&tree_, repo, id); 23 | return; 24 | } 25 | 26 | Tree root(repo, id); 27 | TreeEntry entry; 28 | if (git_tree_entry_bypath(entry.ref(), root, directory.c_str())) 29 | return; 30 | 31 | if (git_tree_entry_type(entry) != GIT_OBJECT_TREE) 32 | return; 33 | 34 | git_tree_lookup(&tree_, repo, git_tree_entry_id(entry)); 35 | } 36 | 37 | Tree::~Tree() 38 | { 39 | git_tree_free(tree_); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mimosa/git/tree.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include 6 | 7 | # include 8 | 9 | namespace mimosa 10 | { 11 | namespace git 12 | { 13 | class Tree : private mimosa::NonCopyable 14 | { 15 | public: 16 | Tree(git_repository * repo, 17 | const git_oid * oid); 18 | Tree(git_repository * repo, 19 | const git_oid * oid, 20 | const std::string & directory); 21 | ~Tree(); 22 | 23 | inline operator git_tree *() const { return tree_; } 24 | 25 | private: 26 | git_tree * tree_; 27 | }; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/http/.gitignore: -------------------------------------------------------------------------------- 1 | request-lexer.cc 2 | request-lexer.hh 3 | request-parser.hh 4 | request-parser.cc 5 | -------------------------------------------------------------------------------- /mimosa/http/byte-range.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | struct ByteRange 8 | { 9 | enum Type { 10 | kStart, 11 | kRange, 12 | kSuffix 13 | }; 14 | 15 | enum Type type_; 16 | int64_t start_; 17 | int64_t end_; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mimosa/http/chunked-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../stream/filter.hh" 4 | # include "../stream/buffered-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | class ChunkedStream : public stream::Filter 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(ChunkedStream); 14 | 15 | explicit ChunkedStream(const stream::BufferedStream::Ptr& stream); 16 | 17 | virtual int64_t write(const char * data, uint64_t nbytes) override; 18 | virtual int64_t read(char * data, uint64_t nbytes) override; 19 | 20 | private: 21 | virtual bool readChunkSize(); 22 | 23 | stream::BufferedStream::Ptr stream_; 24 | uint64_t bytes_left_; 25 | bool first_chunk_; 26 | bool eof_; 27 | }; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/http/client-channel.cc: -------------------------------------------------------------------------------- 1 | #include "../uri/url.hh" 2 | #include "../net/connect.hh" 3 | #include "../stream/net-fd-stream.hh" 4 | #include "../stream/tls-stream.hh" 5 | #include "client-channel.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace http 10 | { 11 | ClientChannel::ClientChannel() 12 | : stream_(), 13 | addr_(nullptr), 14 | addr_len_(0), 15 | read_timeout_(0), 16 | write_timeout_(0), 17 | is_ssl_(false) 18 | { 19 | } 20 | 21 | ClientChannel::~ClientChannel() 22 | = default; 23 | 24 | bool 25 | ClientChannel::connect(const std::string &host, uint16_t port, bool ssl) 26 | { 27 | int fd = net::connectToHost(host, port); 28 | if (fd < 0) 29 | return false; 30 | 31 | stream::NetFdStream::Ptr net_stream = new stream::NetFdStream(fd, true); 32 | stream::Stream::Ptr stream(net_stream); 33 | if (ssl) 34 | stream = new stream::TlsStream(stream, false); 35 | stream_ = new stream::BufferedStream(stream); 36 | return true; 37 | } 38 | 39 | ResponseReader::Ptr 40 | ClientChannel::get(const std::string & raw_url) 41 | { 42 | uri::Url url; 43 | if (!url.parse(raw_url, nullptr)) 44 | return nullptr; 45 | 46 | RequestWriter rw(*this); 47 | rw.setUrl(url); 48 | rw.setMethod(kMethodGet); 49 | rw.setProto(1, 1); 50 | return rw.send(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /mimosa/http/coding.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | /** 8 | * @ingroup Http 9 | */ 10 | enum Coding 11 | { 12 | kCodingIdentity = 1 << 0, 13 | kCodingDeflate = 1 << 1, 14 | kCodingGzip = 1 << 2, 15 | kCodingExi = 1 << 3, 16 | kCodingCompress = 1 << 4, 17 | kCodingPack200_gzip = 1 << 5, 18 | kCodingChunked = 1 << 6, 19 | kCodingSdch = 1 << 7, 20 | kCodingZstd = 1 << 8, 21 | kCodingBr = 1 << 9, 22 | }; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/http/cookie.cc: -------------------------------------------------------------------------------- 1 | #include "cookie.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | Cookie::Cookie() = default; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mimosa/http/dispatch-handler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "dispatch-handler.hh" 4 | #include "request.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | DispatchHandler::DispatchHandler() 11 | : error_handler_(new ErrorHandler) 12 | { 13 | } 14 | 15 | void 16 | DispatchHandler::registerHandler(const std::string & pattern, const Handler::ConstPtr& handler) 17 | { 18 | handlers_[pattern] = handler; 19 | } 20 | 21 | bool 22 | DispatchHandler::handle(RequestReader & request, ResponseWriter & response) const 23 | { 24 | for (const auto & handler : handlers_) 25 | if (!::fnmatch(handler.first.c_str(), request.location().c_str(), 0)) 26 | return handler.second->handle(request, response); 27 | return error_handler_->handle(request, response, kStatusNotFound); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /mimosa/http/dispatch-handler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "handler.hh" 7 | # include "error-handler.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace http 12 | { 13 | /** 14 | * @ingroup Http 15 | */ 16 | class DispatchHandler : public Handler 17 | { 18 | public: 19 | DispatchHandler(); 20 | 21 | /** 22 | * @param pattern a globbing pattern */ 23 | void registerHandler(const std::string & pattern, const Handler::ConstPtr& handler); 24 | virtual bool handle(RequestReader & request, ResponseWriter & response) const; 25 | 26 | inline void setErrorHandler(ErrorHandler::ConstPtr handler) { error_handler_ = handler; } 27 | 28 | private: 29 | std::map handlers_; 30 | ErrorHandler::ConstPtr error_handler_; 31 | }; 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /mimosa/http/docs.txt: -------------------------------------------------------------------------------- 1 | http header fields rfc: http://tools.ietf.org/html/rfc4229 2 | http 1.1 rfc: http://tools.ietf.org/html/rfc2616 3 | http state management: http://tools.ietf.org/html/rfc2965 4 | -------------------------------------------------------------------------------- /mimosa/http/error-handler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "error-handler.hh" 4 | #include "../format/format-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | bool 11 | ErrorHandler::basicResponse(Request & /*request*/, ResponseWriter & response, Status status) 12 | { 13 | response.setStatus(status); 14 | format::format( 15 | response, 16 | "Error %v - %v" 17 | "Error %v - %v", 18 | status, statusToString(status), 19 | status, statusToString(status)); 20 | return true; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mimosa/http/error-handler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "handler.hh" 4 | # include "status.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | /** 11 | * @ingroup Http 12 | */ 13 | class ErrorHandler : public RefCountable 14 | { 15 | public: 16 | inline virtual ~ErrorHandler() {} 17 | 18 | inline virtual bool handle(Request & request, ResponseWriter & response, Status status) const 19 | { 20 | return basicResponse(request, response, status); 21 | } 22 | 23 | static bool basicResponse(Request & request, ResponseWriter & response, Status status); 24 | }; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mimosa/http/handler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../ref-countable.hh" 4 | #include "../non-copyable.hh" 5 | #include "../non-movable.hh" 6 | #include "request-reader.hh" 7 | #include "response-writer.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace http 12 | { 13 | class Request; 14 | 15 | /** 16 | * @ingroup Http 17 | */ 18 | class Handler : public RefCountable, private NonCopyable, private NonMovable 19 | { 20 | public: 21 | virtual ~Handler() {} 22 | virtual bool handle(RequestReader & request, ResponseWriter & response) const = 0; 23 | }; 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /mimosa/http/host-handler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "host-handler.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | HostHandler::HostHandler() 10 | : error_handler_(new ErrorHandler) 11 | { 12 | } 13 | 14 | void 15 | HostHandler::registerHandler(const std::string & pattern, const Handler::ConstPtr& handler) 16 | { 17 | handlers_[pattern] = handler; 18 | } 19 | 20 | bool 21 | HostHandler::handle(RequestReader & request, ResponseWriter & response) const 22 | { 23 | for (const auto & handler : handlers_) 24 | if (!::fnmatch(handler.first.c_str(), request.host().c_str(), 0)) 25 | return handler.second->handle(request, response); 26 | return error_handler_->handle(request, response, kStatusNotFound); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mimosa/http/host-handler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "handler.hh" 7 | # include "error-handler.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace http 12 | { 13 | class HostHandler : public Handler 14 | { 15 | public: 16 | HostHandler(); 17 | 18 | /** 19 | * @param pattern a globbing pattern */ 20 | void registerHandler(const std::string & pattern, const Handler::ConstPtr& handler); 21 | virtual bool handle(RequestReader & request, ResponseWriter & response) const; 22 | 23 | inline void setErrorHandler(ErrorHandler::ConstPtr handler) { error_handler_ = handler; } 24 | 25 | private: 26 | std::map handlers_; 27 | ErrorHandler::ConstPtr error_handler_; 28 | }; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mimosa/http/http.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @defgroup Http Http 4 | 5 | This module provides classes to work with the HTTP protocol, both server 6 | and client side. 7 | 8 | */ 9 | 10 | /** @ingroup Http */ 11 | namespace http {} 12 | -------------------------------------------------------------------------------- /mimosa/http/log-handler.cc: -------------------------------------------------------------------------------- 1 | #include "../net/print.hh" 2 | #include "log.hh" 3 | #include "log-handler.hh" 4 | #include "server-channel.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | bool 11 | LogHandler::handle(RequestReader & request, ResponseWriter & response) const 12 | { 13 | http_log->info("%s %s %s:%s", 14 | net::print(request.channel().remoteAddr(), 15 | request.channel().remoteAddrLen()), 16 | methodString(request.method()), request.host(), 17 | request.rawLocation()); 18 | return handler_->handle(request, response); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mimosa/http/log-handler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "handler.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | /** 10 | * @ingroup Http 11 | */ 12 | class LogHandler : public Handler 13 | { 14 | public: 15 | virtual bool handle(RequestReader & request, ResponseWriter & response) const; 16 | 17 | inline void setHandler(Handler::ConstPtr handler) { handler_ = handler; } 18 | 19 | private: 20 | Handler::ConstPtr handler_; 21 | }; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /mimosa/http/log.cc: -------------------------------------------------------------------------------- 1 | #include "log.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | log::Origin *http_log = new log::Origin("http", log::kInfo); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mimosa/http/log.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../log/log.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | /** 10 | * @ingroup Http 11 | */ 12 | extern log::Origin * http_log; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /mimosa/http/message-reader.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../stream/stream.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | class RequestWriter; 10 | 11 | /** 12 | * @ingroup Http 13 | */ 14 | template 15 | class MessageReader : public stream::Stream, 16 | public Message 17 | { 18 | public: 19 | MIMOSA_DEF_PTR(MessageReader); 20 | 21 | explicit MessageReader(Channel & channel); 22 | 23 | void clear(); 24 | 25 | /** Stream related stuff 26 | * @{ */ 27 | /** @warning this should never be called, will abort */ 28 | virtual int64_t write(const char * data, uint64_t nbytes); 29 | /** reads the body (PUT and POST) */ 30 | virtual int64_t read(char * data, uint64_t nbytes); 31 | /** reads and discards all remaining body data */ 32 | virtual bool flush(); 33 | /** @} */ 34 | 35 | inline Channel & channel() const { return channel_; } 36 | 37 | private: 38 | 39 | friend Channel; 40 | friend RequestWriter; 41 | 42 | bool prepare(); 43 | 44 | Channel & channel_; 45 | stream::Stream::Ptr stream_; 46 | int64_t bytes_left_; 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /mimosa/http/method.cc: -------------------------------------------------------------------------------- 1 | #include "method.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | const char * methodString(Method method) 8 | { 9 | switch (method) 10 | { 11 | case kMethodHead: return "HEAD"; 12 | case kMethodGet: return "GET"; 13 | case kMethodPost: return "POST"; 14 | case kMethodPut: return "PUT"; 15 | case kMethodDelete: return "DELETE"; 16 | case kMethodTrace: return "TRACE"; 17 | case kMethodOptions: return "OPTIONS"; 18 | case kMethodConnect: return "CONNECT"; 19 | case kMethodPatch: return "PATCH"; 20 | 21 | // WebDAV 22 | case kMethodPropfind: return "PROPFIND"; 23 | case kMethodProppatch: return "PROPPATCH"; 24 | case kMethodMkcol: return "MKCOL"; 25 | case kMethodCopy: return "COPY"; 26 | case kMethodMove: return "MOVE"; 27 | case kMethodLock: return "LOCK"; 28 | case kMethodUnlock: return "UNLOCK"; 29 | 30 | // Custom 31 | case kMethodMimosaSymlink: return "MIMOSA_SYMLINK"; 32 | 33 | default: return "(none)"; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mimosa/http/method.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace http 6 | { 7 | /** 8 | * @ingroup Http 9 | */ 10 | enum Method 11 | { 12 | kMethodHead, 13 | kMethodGet, 14 | kMethodPost, 15 | kMethodPut, 16 | kMethodDelete, 17 | kMethodTrace, 18 | kMethodOptions, 19 | kMethodConnect, 20 | kMethodPatch, 21 | 22 | // WebDAV 23 | kMethodPropfind, 24 | kMethodProppatch, 25 | kMethodMkcol, 26 | kMethodCopy, 27 | kMethodMove, 28 | kMethodLock, 29 | kMethodUnlock, 30 | 31 | // Custom?? 32 | kMethodMimosaSymlink, 33 | }; 34 | 35 | /** 36 | * @ingroup Http 37 | */ 38 | const char * methodString(Method method); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /mimosa/http/mime-db.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "../non-copyable.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace http 11 | { 12 | /** 13 | * @ingroup Http 14 | */ 15 | class MimeDb : private NonCopyable 16 | { 17 | public: 18 | static MimeDb & instance(); 19 | 20 | std::string mimeType(const std::string & filename); 21 | 22 | private: 23 | MimeDb(); 24 | 25 | void load(); 26 | 27 | std::unordered_map mime_types_; 28 | }; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mimosa/http/redirect.cc: -------------------------------------------------------------------------------- 1 | #include "response-writer.hh" 2 | #include "redirect.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace http 7 | { 8 | bool redirect(ResponseWriter & response, const std::string & location) 9 | { 10 | response.setStatus(kStatusFound); 11 | response.setLocation(location); 12 | return true; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /mimosa/http/redirect.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "response-writer.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace http 10 | { 11 | /** 12 | * @ingroup Http 13 | */ 14 | bool redirect(ResponseWriter & response, const std::string & location); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /mimosa/http/request-reader.cc: -------------------------------------------------------------------------------- 1 | #include "request-reader.hh" 2 | #include "server-channel.hh" 3 | #include "message-reader.hxx" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | template class MessageReader; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /mimosa/http/request-reader.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "request.hh" 4 | # include "message-reader.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | class ServerChannel; 11 | typedef MessageReader RequestReader; 12 | extern template class MessageReader; 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /mimosa/http/request-writer.cc: -------------------------------------------------------------------------------- 1 | #include "request-writer.hh" 2 | #include "client-channel.hh" 3 | #include "message-writer.hxx" 4 | 5 | namespace mimosa 6 | { 7 | namespace http 8 | { 9 | template class MessageWriter; 10 | 11 | bool 12 | RequestWriter::sendRequest() 13 | { 14 | bool is_ssl = url_.scheme() == uri::kSchemeHttps; 15 | 16 | if (!channel_.connect(url_.host().asStdString(), url_.port(), is_ssl)) 17 | return false; 18 | 19 | if (!sendHeader()) 20 | return false; 21 | return true; 22 | } 23 | 24 | ResponseReader::Ptr 25 | RequestWriter::response() 26 | { 27 | if (!flush()) 28 | return nullptr; 29 | 30 | ResponseReader::Ptr rr = new ResponseReader(channel_); 31 | 32 | bool found = false; 33 | stream::Buffer::Ptr buffer = channel_.stream_->readUntil( 34 | "\r\n\r\n", 5 * 1024, &found); 35 | if (!buffer || !found || !rr->parse(buffer->data(), buffer->size())) 36 | return nullptr; 37 | if (!rr->prepare()) 38 | return nullptr; 39 | return rr; 40 | } 41 | 42 | ResponseReader::Ptr 43 | RequestWriter::send() 44 | { 45 | if (!sendRequest()) 46 | return nullptr; 47 | return response(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mimosa/http/request-writer.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "request.hh" 4 | # include "message-writer.hh" 5 | # include "response-reader.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace http 10 | { 11 | class ClientChannel; 12 | 13 | class RequestWriter : public MessageWriter 14 | { 15 | public: 16 | MIMOSA_DEF_PTR(RequestWriter); 17 | 18 | inline explicit RequestWriter(ClientChannel & channel) 19 | : MessageWriter (channel) 20 | { 21 | } 22 | 23 | bool sendRequest(); 24 | ResponseReader::Ptr response(); 25 | 26 | ResponseReader::Ptr send(); 27 | }; 28 | 29 | extern template class MessageWriter; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /mimosa/http/response-reader.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "response-reader.hh" 5 | #include "server-channel.hh" 6 | #include "chunked-stream.hh" 7 | #include "../format/print.hh" 8 | #include "../stream/zlib-encoder.hh" 9 | #include "log.hh" 10 | #include "client-channel.hh" 11 | #include "message-reader.hxx" 12 | 13 | namespace mimosa 14 | { 15 | namespace http 16 | { 17 | template class MessageReader; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mimosa/http/response-reader.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "response.hh" 4 | # include "message-reader.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | class ClientChannel; 11 | class Request; 12 | 13 | typedef MessageReader ResponseReader; 14 | extern template class MessageReader; 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /mimosa/http/response-writer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "response-writer.hh" 5 | #include "server-channel.hh" 6 | #include "chunked-stream.hh" 7 | #include "../format/print.hh" 8 | #include "../stream/zlib-encoder.hh" 9 | #include "log.hh" 10 | #include "message-writer.hxx" 11 | 12 | namespace mimosa 13 | { 14 | namespace http 15 | { 16 | template class MessageWriter; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mimosa/http/response-writer.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../stream/stream.hh" 4 | # include "../stream/direct-fd-stream.hh" 5 | # include "../stream/buffer.hh" 6 | # include "response.hh" 7 | # include "message-writer.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace http 12 | { 13 | class ServerChannel; 14 | class Request; 15 | 16 | typedef MessageWriter ResponseWriter; 17 | extern template class MessageWriter; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /mimosa/http/samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(key.pem certtool -p --outfile key.pem) 2 | add_custom_target(cert.pem certtool -s --load-privkey key.pem --outfile cert.pem 3 | DEPENDS key.pem) 4 | 5 | add_executable(web-server web-server.cc) 6 | target_link_libraries(web-server mimosa-http) 7 | 8 | add_executable(mget mget.cc) 9 | target_link_libraries(mget mimosa-http) 10 | 11 | add_executable(mput mput.cc) 12 | target_link_libraries(mput mimosa-flat mimosa-http) 13 | 14 | add_executable(mpost mpost.cc) 15 | target_link_libraries(mpost mimosa-flat mimosa-http) 16 | -------------------------------------------------------------------------------- /mimosa/http/samples/mget.cc: -------------------------------------------------------------------------------- 1 | #include "../../init.hh" 2 | #include "../../options/options.hh" 3 | 4 | #include "../client-channel.hh" 5 | #include "../../stream/fd-stream.hh" 6 | #include "../../stream/copy.hh" 7 | 8 | std::string & URL = *mimosa::options::addOption("", "url", "the webpage to download", ""); 9 | std::string & OUT = *mimosa::options::addOption("", "out", "where to save?", ""); 10 | 11 | int main(int argc, char **argv) 12 | { 13 | mimosa::init(argc, argv); 14 | 15 | mimosa::http::ClientChannel cc; 16 | auto response = cc.get(URL); 17 | if (!response) 18 | return 1; 19 | 20 | auto file = mimosa::stream::FdStream::openFile(OUT.c_str(), O_RDWR | O_CREAT | O_TRUNC); 21 | if (!file) 22 | return 1; 23 | 24 | mimosa::stream::copy(*response, *file); 25 | 26 | mimosa::deinit(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /mimosa/http/samples/mpost.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../client-channel.hh" 6 | #include "../../stream/copy.hh" 7 | 8 | std::string & URL = *mimosa::options::addOption("", "url", "the webpage to download", ""); 9 | std::string & DATA = *mimosa::options::addOption("", "data", "data to upload", ""); 10 | 11 | int main(int argc, char **argv) 12 | { 13 | mimosa::init(argc, argv); 14 | 15 | mimosa::http::ClientChannel cc; 16 | mimosa::http::RequestWriter rw(cc); 17 | rw.setUrl(URL); 18 | rw.setMethod(mimosa::http::kMethodPost); 19 | rw.setProto(1, 1); 20 | rw.setContentLength(DATA.size()); 21 | rw.setContentType("application/json"); 22 | if (!rw.sendRequest()) 23 | return 2; 24 | rw.loopWrite((const char *)DATA.data(), DATA.size()); 25 | auto response = rw.response(); 26 | if (!response) 27 | return 3; 28 | 29 | mimosa::stream::DirectFdStream out(STDOUT_FILENO, false); 30 | mimosa::stream::copy(*response, out); 31 | 32 | mimosa::deinit(); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /mimosa/http/samples/mput.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../client-channel.hh" 5 | #include "../../flat/flat.hh" 6 | #include "../../stream/copy.hh" 7 | 8 | std::string & URL = *mimosa::options::addOption("", "url", "the webpage to download", ""); 9 | std::string & IN = *mimosa::options::addOption("", "in", "file to upload", ""); 10 | 11 | int main(int argc, char **argv) 12 | { 13 | mimosa::init(argc, argv); 14 | 15 | mimosa::flat::Flat flat(IN, O_RDONLY, 0666); 16 | if (!flat.ok()) 17 | return 1; 18 | 19 | mimosa::http::ClientChannel cc; 20 | mimosa::http::RequestWriter rw(cc); 21 | rw.setUrl(URL); 22 | rw.setMethod(mimosa::http::kMethodPut); 23 | rw.setProto(1, 1); 24 | rw.setContentLength(flat.size()); 25 | rw.setContentType("image/png"); 26 | if (!rw.sendRequest()) 27 | return 2; 28 | rw.loopWrite((const char *)flat.base(), flat.size()); 29 | auto response = rw.response(); 30 | if (!response) 31 | return 3; 32 | 33 | mimosa::deinit(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /mimosa/http/server.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "handler.hh" 6 | # include "../non-copyable.hh" 7 | # include "../net/server.hh" 8 | # include "../time.hh" 9 | 10 | namespace mimosa 11 | { 12 | namespace http 13 | { 14 | /** 15 | * @ingroup Http 16 | */ 17 | class Server : public net::Server 18 | { 19 | public: 20 | MIMOSA_DEF_PTR(Server); 21 | 22 | Server(); 23 | ~Server(); 24 | 25 | inline void setHandler(Handler::Ptr handler) { handler_ = handler; } 26 | void setSecure(const std::string & cert_file, 27 | const std::string & key_file); 28 | 29 | inline void setReadTimeout(Time timeout) { read_timeout_ = timeout; } 30 | inline void setWriteTimeout(Time timeout) { write_timeout_ = timeout; } 31 | 32 | virtual void serve(int fd, 33 | const ::sockaddr * address, 34 | socklen_t address_len) const override; 35 | 36 | private: 37 | 38 | Time read_timeout_; 39 | Time write_timeout_; 40 | Handler::Ptr handler_; 41 | ::gnutls_certificate_credentials_t x509_cred_; 42 | ::gnutls_priority_t priority_cache_; 43 | ::gnutls_dh_params_t dh_params_; 44 | }; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /mimosa/http/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa-http tst-response.cc tst-request-parser.cc) 2 | target_link_libraries(tst-mimosa-http mimosa-http) 3 | -------------------------------------------------------------------------------- /mimosa/http/time.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "time.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace http 10 | { 11 | std::string time(::time_t t) 12 | { 13 | char buffer[64]; 14 | 15 | ctime_r(&t, buffer); // needs at most 26 bytes 16 | buffer[::strlen(buffer) - 1] = '\0'; // remove trailing \n 17 | return buffer; 18 | } 19 | 20 | ::time_t time(const std::string & str) 21 | { 22 | tm tm{}; 23 | 24 | strptime(str.c_str(), "%a %b %d %H:%M:%S %Y", &tm); 25 | return mktime(&tm); // local time 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /mimosa/http/time.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | namespace mimosa 7 | { 8 | namespace http 9 | { 10 | /** 11 | * @ingroup Http 12 | */ 13 | std::string time(::time_t t = ::time(nullptr)); 14 | 15 | ::time_t time(const std::string & str); 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /mimosa/init.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include "init.hh" 12 | #include "options/options.hh" 13 | #include "uptime.hh" 14 | #include "log/log.hh" 15 | 16 | namespace mimosa 17 | { 18 | static void gnutls_log(int /*level*/, const char *msg) 19 | { 20 | log::info("[gnutls] %s", msg); 21 | } 22 | 23 | void init(int argc, char ** argv) 24 | { 25 | // initialize uptime 26 | uptime(); 27 | 28 | ::signal(SIGPIPE, SIG_IGN); 29 | options::parse(argc, argv); 30 | ::gnutls_global_init(); 31 | ::gnutls_check_version(GNUTLS_VERSION); 32 | ::gnutls_global_set_log_level(0); 33 | ::gnutls_global_set_log_function(gnutls_log); 34 | } 35 | 36 | void deinit() 37 | { 38 | ::gnutls_global_deinit (); 39 | options::deinit(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mimosa/init.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @page initialisation Intialisation rules 4 | 5 | @section the_problem The problem 6 | 7 | The initialisation problem in C++ comes from the "static initialisation Fiasco". 8 | Which is in short, the random order of static initialisation or de-initialisation 9 | which leads to random behaviour and segfaults. 10 | 11 | @section the_solution The solution 12 | 13 | To be safe against this problem, the solution is define safe practices: 14 | - it is safe to initialise static POD types with const expressions 15 | - every modules should provide init()/deinit() functions when they need 16 | to initialize static non-pod data 17 | - it is safe to use, mimosa::option or mimosa::log for static intialisation 18 | as shown in the samples (it has been wrote carefully) 19 | 20 | */ 21 | -------------------------------------------------------------------------------- /mimosa/init.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | void init(int argc, char ** argv); 6 | void deinit(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /mimosa/intrusive-hash-table.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "non-copyable.hh" 6 | 7 | namespace mimosa 8 | { 9 | template 10 | class IntrusiveHashTableHook 11 | { 12 | public: 13 | inline IntrusiveHashTableHook() : next_(nullptr), hash_(0) {} 14 | 15 | Ptr next_; 16 | uint32_t hash_; 17 | }; 18 | 19 | template T::*Member> 20 | class IntrusiveHashTable : public NonCopyable 21 | { 22 | public: 23 | 24 | inline IntrusiveHashTable(size_t capacity = 8); 25 | inline ~IntrusiveHashTable(); 26 | inline IntrusiveHashTable(IntrusiveHashTable && ht); 27 | inline IntrusiveHashTable & operator=(IntrusiveHashTable && ht); 28 | 29 | inline bool empty() const { return size_ == 0; } 30 | inline size_t size() const { return size_; } 31 | inline size_t capacity() const { return capacity_; } 32 | 33 | inline void insert(Ptr entry, bool auto_rehash = true); 34 | 35 | /** 36 | * Rehash to capacity. 37 | * @capacity if 0, then try to find a good size and rehash if necessary. 38 | */ 39 | inline void rehash(size_t capacity = 0); 40 | 41 | inline void remove(Ptr entry, bool auto_rehash = true); 42 | inline void clear(); 43 | 44 | template 45 | inline Ptr find(uint32_t hash, const Eq & eq) const; 46 | 47 | private: 48 | Ptr *buckets_; 49 | size_t size_; 50 | size_t capacity_; 51 | }; 52 | } 53 | 54 | #include "intrusive-hash-table.hxx" 55 | -------------------------------------------------------------------------------- /mimosa/json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | decoder.hh 3 | encoder.hh 4 | DESTINATION include/mimosa/json/) 5 | 6 | add_library(mimosa-json STATIC 7 | encoder.cc 8 | decoder.cc 9 | ) 10 | target_link_libraries(mimosa-json PUBLIC mimosa) 11 | 12 | install(TARGETS mimosa-json 13 | RUNTIME DESTINATION bin 14 | LIBRARY DESTINATION lib 15 | ARCHIVE DESTINATION lib) 16 | 17 | add_subdirectory(tests) 18 | -------------------------------------------------------------------------------- /mimosa/json/encoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../stream/stream.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace json 10 | { 11 | /** 12 | * @ingroup json 13 | * JSON stream encoder. 14 | */ 15 | class Encoder 16 | { 17 | public: 18 | explicit Encoder(stream::Stream::Ptr output); 19 | 20 | bool startObject(); 21 | bool endObject(); 22 | 23 | bool startArray(); 24 | bool endArray(); 25 | 26 | bool pushString(const std::string_view & data); 27 | bool pushNumber(int64_t value); 28 | bool pushFloat(double value); 29 | bool pushBoolean(bool value); 30 | bool pushNull(); 31 | 32 | private: 33 | bool pushSeparator(); 34 | void nextState(); 35 | 36 | enum State 37 | { 38 | kArray, 39 | kArrayNext, 40 | kObjectKey, 41 | kObjectValue, 42 | kObjectNext, 43 | }; 44 | 45 | stream::Stream::Ptr output_; 46 | std::vector state_; 47 | }; 48 | 49 | class SyntaxError 50 | { 51 | }; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /mimosa/json/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa-json 2 | tst-decoder.cc 3 | tst-encoder.cc 4 | ) 5 | 6 | target_link_libraries(tst-mimosa-json mimosa-json) -------------------------------------------------------------------------------- /mimosa/kvs.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | namespace mimosa 7 | { 8 | // XXX remove me 9 | typedef std::unordered_multimap kvs; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /mimosa/locker.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "non-copyable.hh" 4 | #include "non-movable.hh" 5 | 6 | namespace mimosa 7 | { 8 | /** 9 | * @ingroup Sync 10 | */ 11 | template 12 | class Locker : private NonCopyable, private NonMovable 13 | { 14 | public: 15 | inline explicit Locker(T & mutex) : mutex_(mutex) { mutex_.lock(); } 16 | inline ~Locker() { mutex_.unlock(); } 17 | private: 18 | T & mutex_; 19 | }; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /mimosa/log/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | level.hh 3 | log.hh 4 | origin.hh 5 | DESTINATION include/mimosa/log/) 6 | 7 | add_subdirectory(tests) 8 | -------------------------------------------------------------------------------- /mimosa/log/level.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace log 8 | { 9 | enum Level 10 | { 11 | kDebug = 0, ///< here goes debug information 12 | kInfo = 1, ///< here goes information messages 13 | kWarning = 2, ///< here goes warning 14 | kError = 3, ///< here goes unexpected errors 15 | kCritical = 4, ///< here goes events which should never happend (like an assert) 16 | /// but are recoverable 17 | kFatal = 5, ///< here goes fatal errors, after that the program should exit 18 | }; 19 | 20 | extern Level global_level; 21 | 22 | /// converts a level into a string 23 | const char * levelName(Level level); 24 | 25 | /// converts a string into a level, fallback to Info when parse failed 26 | Level parseLevel(const char * str); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/log/log.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../format/format.hh" 6 | # include "level.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace log 11 | { 12 | class Origin; 13 | 14 | void log(Level level, const Origin * origin, const std::string & msg); 15 | 16 | /** 17 | * Closes the log file descriptor if the option -log-file is not empty. 18 | * The next call to log() will re-open it. 19 | */ 20 | void release(); 21 | 22 | # define IMPL_LOG(Level, Name) \ 23 | template \ 24 | inline void \ 25 | Name(const char * fmt, Args ... args) \ 26 | { \ 27 | if (Level >= global_level) \ 28 | log(Level, nullptr, format::str(fmt, args...)); \ 29 | } 30 | 31 | IMPL_LOG(kDebug, debug); 32 | IMPL_LOG(kInfo, info); 33 | IMPL_LOG(kWarning, warning); 34 | IMPL_LOG(kError, error); 35 | IMPL_LOG(kCritical, critical); 36 | IMPL_LOG(kFatal, fatal); 37 | 38 | # undef IMPL_LOG 39 | 40 | } 41 | } 42 | 43 | # include "origin.hh" 44 | 45 | -------------------------------------------------------------------------------- /mimosa/log/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(hello-log EXCLUDE_FROM_ALL hello-log.cc) 2 | target_link_libraries(hello-log mimosa) 3 | -------------------------------------------------------------------------------- /mimosa/log/tests/hello-log.cc: -------------------------------------------------------------------------------- 1 | #include "../log.hh" 2 | #include "../../init.hh" 3 | 4 | auto * network = new mimosa::log::Origin("network", mimosa::log::Info); 5 | 6 | int main(int argc, char ** argv) 7 | { 8 | mimosa::init(argc, argv); 9 | 10 | MIMOSA_LOG(Debug, network, "debug message"); 11 | MIMOSA_LOG(Info, network, "info message"); 12 | MIMOSA_LOG(Warning, network, "warning message"); 13 | MIMOSA_LOG(Error, network, "error message"); 14 | MIMOSA_LOG(Critical, network, "critical message"); 15 | MIMOSA_LOG(Fatal, network, "fatal message %d", 1); 16 | 17 | mimosa::deinit(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /mimosa/net/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | accept.hh 3 | connect.hh 4 | io.hh 5 | print.hh 6 | server.hh 7 | DESTINATION include/mimosa/net/) 8 | -------------------------------------------------------------------------------- /mimosa/net/accept.cc: -------------------------------------------------------------------------------- 1 | #include "common.hh" 2 | 3 | #include "io.hh" 4 | #include "accept.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace net 9 | { 10 | int accept(int socket, struct sockaddr * address, socklen_t * address_len, 11 | Time timeout) 12 | { 13 | if (!waitForFdReady(socket, POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI, timeout)) 14 | return -1; 15 | return ::accept(socket, address, address_len); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mimosa/net/accept.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # 4 | 5 | #include 6 | 7 | #include "../time.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace net 12 | { 13 | int accept(int socket, ::sockaddr * address, socklen_t * address_len, 14 | Time timeout); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mimosa/net/common.hh: -------------------------------------------------------------------------------- 1 | #include "../preproc.hh" 2 | 3 | #ifdef MIMOSA_WIN 4 | # include 5 | # include 6 | #endif 7 | 8 | #ifdef MIMOSA_UNIX 9 | # include 10 | # include 11 | #endif 12 | -------------------------------------------------------------------------------- /mimosa/net/connect.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include 7 | # include 8 | 9 | # include "../time.hh" 10 | # include "../string-ref.hh" 11 | 12 | namespace mimosa 13 | { 14 | namespace net 15 | { 16 | int connect(int socket, const struct sockaddr *address, 17 | socklen_t address_len, Time timeout = 0); 18 | 19 | int connectToHost(const std::string &host, uint16_t port, Time timeout = 0); 20 | 21 | int connectToUnixSocket(const std::string & path, 22 | Time timeout = 0); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/net/io.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../compat/uio.hh" 4 | 5 | #include "../time.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace net 10 | { 11 | bool waitForFdReady(int fd, int events, Time timeout); 12 | 13 | int64_t write(int fd, const char * data, uint64_t nbytes, Time timeout); 14 | int64_t writev(int fd, const ::iovec *iov, int iovcnt, Time timeout); 15 | int64_t read(int fd, char * data, uint64_t nbytes, Time timeout); 16 | int64_t readv(int fd, const ::iovec *iov, int iovcnt, Time timeout); 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /mimosa/net/print.cc: -------------------------------------------------------------------------------- 1 | #if defined(__unix__) || defined(__APPLE__) 2 | # include 3 | #endif 4 | 5 | #ifdef __WIN32__ 6 | # include 7 | #endif 8 | 9 | #include "print.hh" 10 | 11 | namespace mimosa 12 | { 13 | namespace net 14 | { 15 | std::string print(const struct ::sockaddr *addr, ::socklen_t len) 16 | { 17 | char host[80] = { '\0' }; 18 | 19 | getnameinfo(addr, len, host, sizeof (host), nullptr, 0, NI_NUMERICHOST); 20 | return host; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mimosa/net/print.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) 6 | # include 7 | # include 8 | #endif 9 | 10 | #ifdef __WIN32__ 11 | # include 12 | #endif 13 | 14 | #include 15 | 16 | namespace mimosa 17 | { 18 | namespace net 19 | { 20 | std::string print(const struct ::sockaddr *addr, ::socklen_t len); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /mimosa/net/server.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | # include 6 | 7 | # include 8 | 9 | # include "../function.hh" 10 | # include "../thread.hh" 11 | 12 | namespace mimosa 13 | { 14 | namespace net 15 | { 16 | class Server : public RefCountable, private NonCopyable, private NonMovable 17 | { 18 | public: 19 | Server(); 20 | ~Server(); 21 | 22 | bool listenUnix(const std::string & path); 23 | bool listenInet4(uint16_t port, const struct ::in_addr * interface = 0); 24 | bool listenInet6(uint16_t port, const struct ::in6_addr * interface = 0); 25 | 26 | inline int fd() const { return fd_; } 27 | int accept(::sockaddr * address = nullptr, 28 | ::socklen_t * address_len = nullptr, 29 | Time timeout = 0) const; 30 | 31 | /// @param new_thread if true, after accept return a valid fd, serveOne 32 | /// will call serve(fd) in a new thread 33 | void serveOne(Time accept_timeout = 0, bool new_thread = true) const; 34 | 35 | void close(); 36 | 37 | /// The default implementation just closes the fd. 38 | virtual void serve(int fd, 39 | const ::sockaddr * address, 40 | socklen_t address_len) const; 41 | 42 | private: 43 | int fd_; 44 | }; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /mimosa/non-copyable.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | class NonCopyable 6 | { 7 | protected: 8 | constexpr NonCopyable() noexcept = default; 9 | 10 | // allow move stuff 11 | inline NonCopyable(NonCopyable &&) noexcept {} 12 | inline NonCopyable & operator=(NonCopyable&&) noexcept { return *this; } 13 | 14 | private: 15 | NonCopyable(const NonCopyable &) = delete; 16 | NonCopyable & operator=(const NonCopyable &) = delete; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /mimosa/non-movable.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | class NonMovable 6 | { 7 | protected: 8 | constexpr NonMovable() noexcept = default; 9 | 10 | inline NonMovable(NonMovable &&) = delete; 11 | inline NonMovable & operator=(NonMovable&&) = delete; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /mimosa/options/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | options.hh 3 | DESTINATION include/mimosa/options/) 4 | 5 | add_subdirectory(tests) 6 | -------------------------------------------------------------------------------- /mimosa/options/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(hello-opts EXCLUDE_FROM_ALL hello-opts.cc) 2 | target_link_libraries(hello-opts mimosa) 3 | 4 | add_executable(duplicate-opts EXCLUDE_FROM_ALL duplicate-opts.cc) 5 | target_link_libraries(duplicate-opts mimosa) 6 | -------------------------------------------------------------------------------- /mimosa/options/tests/duplicate-opts.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * This test is meant to check that having two time the same option 3 | * will generate a failure. 4 | */ 5 | 6 | #include "../options.hh" 7 | 8 | bool * enable_x = mimosa::options::addSwitch("group", "enable-x", "enables feature x"); 9 | bool * enable_y = mimosa::options::addSwitch("group", "enable-x", "enables feature x"); 10 | 11 | int main(int argc, char ** argv) 12 | { 13 | mimosa::options::parse(argc, argv); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /mimosa/options/tests/hello-opts.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../options.hh" 4 | 5 | bool * enable_x = mimosa::options::addSwitch("group", "enable-x", "enables feature x"); 6 | std::string * toto = mimosa::options::addOption( 7 | "group2", "toto", "toto's name", "(unamed toto)"); 8 | 9 | int main(int argc, char ** argv) 10 | { 11 | mimosa::options::parse(argc, argv); 12 | 13 | std::cout << "feature x " << (*enable_x ? "enabled" : "disabled") << std::endl; 14 | std::cout << "toto's name: " << *toto << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /mimosa/preproc.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__linux) || defined(__linux__) 4 | # define MIMOSA_LINUX 5 | # define MIMOSA_UNIX 6 | #elif defined(__APPLE__) 7 | # define MIMOSA_MAC 8 | # define MIMOSA_UNIX 9 | #elif defined(__unix__) || defined(__HAIKU__) 10 | # define MIMOSA_HAIKU 11 | # define MIMOSA_UNIX 12 | #elif defined(__WIN32__) 13 | # define MIMOSA_WIN 14 | #endif 15 | -------------------------------------------------------------------------------- /mimosa/priviledge-drop.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | bool priviledgeDrop(const std::string & chroot, 8 | const std::string & user, 9 | const std::string & group); 10 | 11 | /** 12 | * This function registers options for chroot and userid/groupid. 13 | * 14 | * When you call it, it will check if we are root, and then chroot 15 | * and change user/group. 16 | */ 17 | bool priviledgeDrop(); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /mimosa/redis/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | context.hh 3 | log.hh 4 | redis.hh 5 | reply.hh 6 | DESTINATION include/mimosa/redis/) 7 | 8 | add_library(mimosa-redis STATIC log.cc) 9 | target_link_libraries(mimosa-redis PUBLIC mimosa) 10 | -------------------------------------------------------------------------------- /mimosa/redis/context.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../non-copyable.hh" 6 | # include "log.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace redis 11 | { 12 | class Context : public NonCopyable 13 | { 14 | public: 15 | inline Context() : ctx_(nullptr) {} 16 | inline Context(Context && ctx) : ctx_(ctx.ctx_) { ctx.ctx_ = nullptr; } 17 | inline ~Context() { 18 | if (ctx_) 19 | redisFree(ctx_); 20 | } 21 | 22 | inline Context & operator =(Context && ctx) { 23 | if (ctx_) 24 | redisFree(ctx_); 25 | ctx_ = ctx.ctx_; 26 | ctx.ctx_ = nullptr; 27 | return *this; 28 | } 29 | 30 | inline bool connect(const char *ip, int port) { 31 | if (ctx_) 32 | redisFree(ctx_); 33 | ctx_ = redisConnect(ip, port); 34 | return ctx_; 35 | } 36 | 37 | inline operator redisContext *() const { return ctx_; } 38 | 39 | inline Reply command(const char *format, ...) 40 | { 41 | va_list args; 42 | va_start(args, format); 43 | Reply reply(redisvCommand(ctx_, format, args)); 44 | 45 | // check and log 46 | if (reply->type == REDIS_REPLY_ERROR) 47 | redis_log->error("redis command failed: %s", reply->str); 48 | 49 | return reply; 50 | } 51 | 52 | private: 53 | redisContext *ctx_; 54 | }; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /mimosa/redis/log.cc: -------------------------------------------------------------------------------- 1 | #include "log.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace redis 6 | { 7 | log::Origin * redis_log = new log::Origin("redis", log::kWarning); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mimosa/redis/log.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../log/log.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace redis 8 | { 9 | extern log::Origin * redis_log; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /mimosa/redis/redis.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "reply.hh" 4 | # include "context.hh" 5 | 6 | -------------------------------------------------------------------------------- /mimosa/redis/reply.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include 6 | 7 | namespace mimosa 8 | { 9 | namespace redis 10 | { 11 | class Reply : public NonCopyable 12 | { 13 | public: 14 | inline Reply(Reply && reply) : reply_(reply.reply_) { reply.reply_ = nullptr; } 15 | inline explicit Reply(void *reply) : reply_(reinterpret_cast (reply)) {} 16 | inline ~Reply() { 17 | if (reply_) 18 | freeReplyObject(reply_); 19 | } 20 | 21 | inline Reply & operator =(Reply && reply) { 22 | if (reply_) 23 | freeReplyObject(reply_); 24 | reply_ = reply.reply_; 25 | reply.reply_ = nullptr; 26 | return *this; 27 | } 28 | 29 | operator redisReply* () const { return reply_; } 30 | redisReply * operator ->() const { return reply_; } 31 | 32 | private: 33 | redisReply *reply_; 34 | }; 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /mimosa/rpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | basic-call.hh 3 | bencode.hh 4 | call.hh 5 | channel.hh 6 | exception.hh 7 | http-call.hh 8 | json.hh 9 | log.hh 10 | protocol.hh 11 | server.hh 12 | service.hh 13 | service-map.hh 14 | DESTINATION include/mimosa/rpc/) 15 | 16 | add_library(mimosa-rpc STATIC 17 | basic-call.cc 18 | channel.cc 19 | http-call.cc 20 | json.cc 21 | log.cc 22 | server.cc 23 | service.cc 24 | service-map.cc) 25 | target_link_libraries(mimosa-rpc PUBLIC mimosa PkgConfig::protobuf) 26 | 27 | add_library(mimosa-rpc-bencode STATIC bencode.cc) 28 | target_link_libraries(mimosa-rpc-bencode PUBLIC mimosa-rpc mimosa-bencode) 29 | 30 | add_library(mimosa-rpc-json STATIC json.cc) 31 | target_link_libraries(mimosa-rpc-json PUBLIC mimosa-rpc mimosa-json) 32 | 33 | install(TARGETS mimosa-rpc mimosa-rpc-bencode mimosa-rpc-json 34 | RUNTIME DESTINATION bin 35 | LIBRARY DESTINATION lib 36 | ARCHIVE DESTINATION lib) 37 | 38 | add_subdirectory(gen) 39 | add_subdirectory(samples) 40 | -------------------------------------------------------------------------------- /mimosa/rpc/basic-call.cc: -------------------------------------------------------------------------------- 1 | #include "basic-call.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace rpc 6 | { 7 | BasicCall::BasicCall(google::protobuf::Message * request, 8 | google::protobuf::Message * response) 9 | : request_(request), 10 | response_(response) 11 | { 12 | } 13 | 14 | BasicCall::~BasicCall() 15 | { 16 | Mutex::Locker locker(mutex_); 17 | delete request_; 18 | delete response_; 19 | request_ = nullptr; 20 | response_ = nullptr; 21 | } 22 | 23 | void 24 | BasicCall::wait() 25 | { 26 | if (is_finished_ || is_canceled_) 27 | return; 28 | 29 | Mutex::Locker locker(mutex_); 30 | if (is_finished_ || is_canceled_) 31 | return; 32 | condition_.wait(mutex_); 33 | } 34 | 35 | void 36 | BasicCall::timedWait(Time timeout) 37 | { 38 | if (is_finished_ || is_canceled_) 39 | return; 40 | 41 | Mutex::Locker locker(mutex_); 42 | if (is_finished_ || is_canceled_) 43 | return; 44 | condition_.timedWait(mutex_, timeout); 45 | } 46 | 47 | void 48 | BasicCall::cancel() 49 | { 50 | Mutex::Locker locker(mutex_); 51 | is_finished_ = true; 52 | is_canceled_ = true; 53 | condition_.wakeAll(); 54 | } 55 | 56 | void 57 | BasicCall::finished() 58 | { 59 | Mutex::Locker locker(mutex_); 60 | is_finished_ = true; 61 | condition_.wakeAll(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /mimosa/rpc/bencode.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "../bencode/encoder.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace rpc 11 | { 12 | void encode(bencode::Encoder & enc, 13 | const google::protobuf::Message * msg); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /mimosa/rpc/call.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "basic-call.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace rpc 8 | { 9 | template 10 | class Call : public BasicCall 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(Call); 14 | 15 | inline explicit Call(Request * request = nullptr, 16 | Response * response = nullptr) 17 | : BasicCall(request ? : new Request(), 18 | response ? : new Response()) 19 | { 20 | } 21 | 22 | inline Request & request() const { return *reinterpret_cast(request_); } 23 | inline Response & response() const { return *reinterpret_cast(response_); } 24 | 25 | inline void allocateMessages() 26 | { 27 | request_ = request_ ? : new Request; 28 | response_ = response_ ? : new Response; 29 | } 30 | }; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /mimosa/rpc/exception.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | namespace rpc 6 | { 7 | class MissingRequiredField 8 | { 9 | }; 10 | 11 | class InvalidFormat 12 | { 13 | }; 14 | 15 | class FieldAlreadySet 16 | { 17 | }; 18 | 19 | class InvalidEnumValue 20 | { 21 | }; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /mimosa/rpc/gen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(protoc-gen-mimosa protoc-gen-mimosa.cc) 2 | target_link_libraries(protoc-gen-mimosa protoc PkgConfig::protobuf pthread z) 3 | 4 | install(TARGETS protoc-gen-mimosa 5 | RUNTIME DESTINATION bin 6 | LIBRARY DESTINATION lib 7 | ARCHIVE DESTINATION lib) 8 | -------------------------------------------------------------------------------- /mimosa/rpc/http-call.cc: -------------------------------------------------------------------------------- 1 | #include "../stream/string-stream.hh" 2 | #include "../stream/copy.hh" 3 | #include "../http/client-channel.hh" 4 | #include "http-call.hh" 5 | #include "json.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace rpc 10 | { 11 | 12 | bool httpCall(const std::string &url, 13 | const google::protobuf::Message &request, 14 | google::protobuf::Message *response) 15 | { 16 | http::ClientChannel cc; 17 | http::RequestWriter::Ptr rw = new http::RequestWriter(cc); 18 | 19 | /* request body (JSON) */ 20 | stream::StringStream::Ptr data = new stream::StringStream; 21 | jsonEncode(data.get(), request); 22 | 23 | /* request header */ 24 | rw->setUrl(url); 25 | rw->setMethod(http::kMethodPost); 26 | rw->setProto(1, 1); 27 | rw->setContentType("application/json"); 28 | rw->setContentLength(data->str().size()); 29 | if (!rw->sendRequest()) 30 | return false; 31 | 32 | stream::copy(*data, *rw); 33 | 34 | /* decode response */ 35 | auto rr = rw->response(); 36 | if (!rr) 37 | return false; 38 | 39 | if (response) 40 | jsonDecode(rr.get(), response); 41 | 42 | return true; 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mimosa/rpc/http-call.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "json.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace rpc 8 | { 9 | bool httpCall(const std::string &url, 10 | const google::protobuf::Message &request, 11 | google::protobuf::Message *response); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /mimosa/rpc/json.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "../json/encoder.hh" 7 | # include "../json/decoder.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace rpc 12 | { 13 | void jsonEncode(json::Encoder & enc, 14 | const google::protobuf::Message & msg); 15 | 16 | void jsonEncode(stream::Stream::Ptr output, 17 | const google::protobuf::Message & msg); 18 | 19 | void jsonDecode(json::Decoder & dec, 20 | google::protobuf::Message * msg); 21 | 22 | void jsonDecode(stream::Stream::Ptr input, 23 | google::protobuf::Message * msg); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /mimosa/rpc/log.cc: -------------------------------------------------------------------------------- 1 | #include "log.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace rpc 6 | { 7 | log::Origin *rpc_log = new log::Origin("rpc", log::kInfo); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mimosa/rpc/log.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../log/log.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace rpc 8 | { 9 | /** 10 | * @ingroup Http 11 | */ 12 | extern log::Origin * rpc_log; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /mimosa/rpc/protocol.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../endian.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace rpc 10 | { 11 | enum MsgType 12 | { 13 | kClose = 0x01, 14 | kCall = 0x02, 15 | kResult = 0x03, 16 | kError = 0x04, 17 | }; 18 | 19 | enum ErrorType 20 | { 21 | kSucceed = 0x00, 22 | kCancel = 0x01, 23 | kInvalidMsg = 0x02, 24 | kServiceNotFound = 0x03, 25 | kMethodNotFound = 0x04, 26 | kInternalError = 0x05, 27 | kDuplicateTag = 0x06, 28 | kNotImplemented = 0x07, 29 | }; 30 | 31 | enum TagOrigin 32 | { 33 | kOriginMe = 0x00, 34 | kOriginYou = 0x01, 35 | }; 36 | 37 | struct Msg 38 | { 39 | uint8_t type_; 40 | } __attribute__((packed)); 41 | 42 | struct MsgClose : public Msg 43 | { 44 | } __attribute__((packed)); 45 | 46 | struct MsgCall : public Msg 47 | { 48 | uint32_t tag_; 49 | uint32_t service_id_; 50 | uint32_t method_id_; 51 | uint32_t rq_size_; 52 | char rq_[0]; 53 | } __attribute__((packed)); 54 | 55 | struct MsgResult : public Msg 56 | { 57 | uint32_t tag_; 58 | uint32_t rp_size_; 59 | char rp_[0]; 60 | } __attribute__((packed)); 61 | 62 | struct MsgError : public Msg 63 | { 64 | uint32_t tag_; 65 | uint8_t tag_origin_; 66 | uint8_t error_; 67 | } __attribute__((packed)); 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /mimosa/rpc/rpc.doch: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | @page RPC 4 | 5 | @section Protocol 6 | 7 | @verbatim 8 | connection: message*; 9 | message: CLOSE | 10 | CALL tag service_id method_id msg_size msg | 11 | RESULT tag msg_size msg | 12 | ERROR tag tag_origin error; 13 | 14 | CLOSE: 0x01 (8bits le); 15 | CALL: 0x02 (8bits le); 16 | RESULT: 0x03 (8bits le); 17 | ERROR: 0x04 (8bits le); 18 | 19 | error: CANCEL (0x01 8bits le) | 20 | INVALID_MSG (0x02 8bits le) | 21 | SERVICE_NOT_FOUND (0x03 8bits le) | 22 | METHOD_NOT_FOUND (0x04 8bits le) | 23 | INTERNAL_ERROR (0x05 8bits le) | 24 | DUPLICATE_TAG (0x06 8bits le); 25 | 26 | tag_origin: ORIGIN_ME (0x00 8bits le) | 27 | ORIGIN_YOU (0x01 8bits le) 28 | 29 | tag: (32bits le); 30 | service_id: crc32(service_full_name) (32bits le); 31 | method_id: crc32(method_name) (32bits le); 32 | msg_size: len(msg) (32bits le); 33 | msg: raw data (protobuf) 34 | @endverbatim 35 | 36 | */ 37 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/.gitignore: -------------------------------------------------------------------------------- 1 | kv-db.pb.cc 2 | kv-db.pb.h 3 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_protoc(kv-db) 2 | 3 | add_library(rpc-kv-db-proto kv-db.pb.cc) 4 | 5 | add_executable(rpc-kv-db kv-db.cc database.cc) 6 | target_link_libraries(rpc-kv-db PUBLIC rpc-kv-db-proto mimosa-rpc) 7 | 8 | add_executable(rpc-kv-client kv-db-client.cc) 9 | target_link_libraries(rpc-kv-client PUBLIC rpc-kv-db-proto mimosa-rpc) 10 | 11 | # add_executable(rpc-kv-db-http kv-db-http.cc database.cc) 12 | # target_link_libraries(rpc-kv-db-http rpc-kv-db-proto mimosa-rpc-http) 13 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/database.cc: -------------------------------------------------------------------------------- 1 | #include "database.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace rpc 6 | { 7 | namespace samples 8 | { 9 | bool 10 | Database::get(pb::Key & request, pb::Result & response) 11 | { 12 | SharedMutex::ReadLocker locker(lock_); 13 | printf("get(%s)\n", request.key().c_str()); 14 | auto it = kv_.find(request.key()); 15 | if (it == kv_.end()) 16 | response.set_status(pb::kNotFound); 17 | else 18 | { 19 | response.set_value(it->second); 20 | response.set_status(pb::kOk); 21 | } 22 | return true; 23 | } 24 | 25 | bool 26 | Database::set(pb::KeyValue & request, pb::Result & response) 27 | { 28 | SharedMutex::ReadLocker locker(lock_); 29 | printf("set(%s, %s)\n", request.key().c_str(), 30 | request.value().c_str()); 31 | kv_[request.key()] = request.value(); 32 | response.set_status(pb::kOk); 33 | return true; 34 | } 35 | 36 | bool 37 | Database::del(pb::Key & request, pb::Result & response) 38 | { 39 | SharedMutex::Locker locker(lock_); 40 | printf("del(%s)\n", request.key().c_str()); 41 | auto it = kv_.find(request.key()); 42 | if (it == kv_.end()) 43 | response.set_status(pb::kNotFound); 44 | else 45 | { 46 | kv_.erase(it); 47 | response.set_status(pb::kOk); 48 | } 49 | return true; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/database.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "kv-db.pb.h" 6 | 7 | namespace mimosa 8 | { 9 | namespace rpc 10 | { 11 | namespace samples 12 | { 13 | class Database : public pb::Database::Server 14 | { 15 | public: 16 | // You have to implement the following rpc methods 17 | virtual bool get(pb::Key & request, pb::Result & response); 18 | 19 | virtual bool set(pb::KeyValue & request, pb::Result & response); 20 | 21 | virtual bool del(pb::Key & request, pb::Result & response); 22 | // End of rpc methods 23 | 24 | private: 25 | SharedMutex lock_; 26 | std::map kv_; 27 | }; 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/kv-db-http.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "database.hh" 6 | 7 | using namespace mimosa; 8 | 9 | uint16_t & PORT = *options::addOption("", "port", "the port to use", 4242); 10 | 11 | int main(int argc, char ** argv) 12 | { 13 | mimosa::init(argc, argv); 14 | 15 | auto handler = new mimosa::rpc::samples::pb::DatabaseHttpHandler(new rpc::samples::Database, "/db/"); 16 | 17 | http::Server::Ptr server(new http::Server); 18 | server->setReadTimeout(0); 19 | server->setWriteTimeout(0); 20 | server->setHandler(handler); 21 | if (!server->listenInet4(PORT)) { 22 | fprintf(stderr, "failed to bind on %d: %m\n", PORT); 23 | return 1; 24 | } 25 | printf("listen on %d succeed\n", PORT); 26 | 27 | while (true) 28 | server->serveOne(0, false); 29 | 30 | mimosa::deinit(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/kv-db.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "database.hh" 6 | 7 | using namespace mimosa; 8 | 9 | uint16_t & PORT = *options::addOption("", "port", "the port to use", 4242); 10 | 11 | int main(int argc, char ** argv) 12 | { 13 | mimosa::init(argc, argv); 14 | 15 | rpc::ServiceMap::Ptr service_map = new rpc::ServiceMap; 16 | service_map->add(new rpc::samples::Database); 17 | 18 | rpc::Server::Ptr server = new rpc::Server; 19 | server->setServiceMap(service_map.get()); 20 | server->listenInet4(PORT); 21 | 22 | while (true) 23 | server->serveOne(); 24 | 25 | mimosa::deinit(); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /mimosa/rpc/samples/kv-db.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package mimosa.rpc.samples.pb; 4 | 5 | enum Status 6 | { 7 | kOk = 0; 8 | kNotFound = 1; 9 | kInternalError = 2; 10 | } 11 | 12 | message Key 13 | { 14 | bytes key = 1; 15 | } 16 | 17 | message KeyValue 18 | { 19 | bytes key = 1; 20 | bytes value = 2; 21 | } 22 | 23 | message Result 24 | { 25 | Status status = 1; 26 | bytes value = 2; 27 | } 28 | 29 | service Database 30 | { 31 | rpc get(Key) returns (Result); 32 | rpc set(KeyValue) returns (Result); 33 | rpc del(Key) returns (Result); 34 | } 35 | -------------------------------------------------------------------------------- /mimosa/rpc/server.cc: -------------------------------------------------------------------------------- 1 | #include "../stream/fd-stream.hh" 2 | #include "server.hh" 3 | #include "channel.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace rpc 8 | { 9 | Server::Server() 10 | = default; 11 | 12 | void 13 | Server::serve(int fd, 14 | const ::sockaddr * /*address*/, 15 | socklen_t /*address_len*/) const 16 | { 17 | stream::FdStream::Ptr stream = new stream::FdStream(fd); 18 | Channel::Ptr channel = new Channel(stream.get(), service_map_); 19 | channel->start(); 20 | channel->wait(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mimosa/rpc/server.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../net/server.hh" 4 | # include "service-map.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace rpc 9 | { 10 | class Server : public net::Server 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(Server); 14 | 15 | Server(); 16 | 17 | inline ServiceMap::ConstPtr serviceMap() const { return service_map_; } 18 | inline void setServiceMap(ServiceMap::ConstPtr service_map) 19 | { service_map_ = service_map; } 20 | 21 | virtual void serve(int fd, 22 | const ::sockaddr * address, 23 | socklen_t address_len) const; 24 | 25 | protected: 26 | ServiceMap::ConstPtr service_map_; 27 | }; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/rpc/service-map.cc: -------------------------------------------------------------------------------- 1 | #include "service-map.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace rpc 6 | { 7 | ServiceMap::~ServiceMap() 8 | { 9 | SharedMutex::Locker locker(lock_); 10 | } 11 | 12 | Service::Ptr 13 | ServiceMap::find(uint32_t service_id) const 14 | { 15 | SharedMutex::ReadLocker locker(lock_); 16 | auto it = services_.find(service_id); 17 | if (it == services_.end()) 18 | return nullptr; 19 | return it->second; 20 | } 21 | 22 | void 23 | ServiceMap::add(const Service::Ptr& service) 24 | { 25 | SharedMutex::Locker locker(lock_); 26 | services_[service->id()] = service; 27 | } 28 | 29 | void 30 | ServiceMap::remove(const Service::Ptr& service) 31 | { 32 | SharedMutex::Locker locker(lock_); 33 | services_.erase(service->id()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/rpc/service-map.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../ref-countable.hh" 6 | # include "../shared-mutex.hh" 7 | # include "service.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace rpc 12 | { 13 | class ServiceMap : public RefCountable 14 | { 15 | public: 16 | ~ServiceMap(); 17 | 18 | Service::Ptr find(uint32_t service_id) const; 19 | 20 | void add(const Service::Ptr& service); 21 | void remove(const Service::Ptr& service); 22 | 23 | private: 24 | mutable SharedMutex lock_; 25 | std::map services_; 26 | }; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/rpc/service.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "service.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace rpc 8 | { 9 | Service::CallMethodStatus 10 | Service::callMethod(BasicCall::Ptr /*call*/, 11 | const char * /*request_data*/, 12 | uint32_t /*request_size*/) 13 | { 14 | assert(false && "should not get called!"); 15 | return kNotImplemented; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mimosa/rpc/service.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../ref-countable.hh" 6 | # include "basic-call.hh" 7 | # include "protocol.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace rpc 12 | { 13 | class Channel; 14 | 15 | class Service : public RefCountable, private NonCopyable, private NonMovable 16 | { 17 | public: 18 | 19 | enum CallMethodStatus 20 | { 21 | kSucceed = rpc::kSucceed, 22 | kMethodNotFound = rpc::kMethodNotFound, 23 | kNotImplemented = rpc::kNotImplemented, 24 | kInvalidMsg = rpc::kInvalidMsg, 25 | }; 26 | 27 | virtual ~Service() {} 28 | 29 | virtual uint32_t id() const = 0; 30 | virtual const char * name() const = 0; 31 | 32 | protected: 33 | friend class Channel; 34 | 35 | virtual CallMethodStatus callMethod(BasicCall::Ptr call, 36 | const char * request_data, 37 | uint32_t request_size); 38 | }; 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /mimosa/shared-locker.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "non-copyable.hh" 4 | #include "non-movable.hh" 5 | 6 | namespace mimosa 7 | { 8 | /** 9 | * @ingroup Sync 10 | */ 11 | template 12 | class SharedLocker : private NonCopyable, private NonMovable 13 | { 14 | public: 15 | 16 | inline SharedLocker(T & rwlock) 17 | : rwlock_(rwlock) 18 | { 19 | rwlock_.sharedLock(); 20 | } 21 | 22 | inline ~SharedLocker() 23 | { 24 | rwlock_.unlock(); 25 | } 26 | 27 | private: 28 | T & rwlock_; 29 | }; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /mimosa/singleton.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mimosa 6 | { 7 | /** 8 | * @warning NOT THREAD SAFE, you need to manualy call release to ensure 9 | * resources liberation. 10 | * 11 | * Helpers to implement a singleton. 12 | * Though, you should follow the @ref initialisation rule. 13 | */ 14 | template 15 | class Singleton 16 | { 17 | public: 18 | static T & instance(); 19 | static void release(); 20 | 21 | protected: 22 | static std::atomic instance_; 23 | }; 24 | } 25 | 26 | # include "singleton.hxx" 27 | 28 | -------------------------------------------------------------------------------- /mimosa/singleton.hxx: -------------------------------------------------------------------------------- 1 | namespace mimosa 2 | { 3 | template 4 | std::atomic Singleton::instance_ = {nullptr}; 5 | 6 | template 7 | T & 8 | Singleton::instance() 9 | { 10 | if (!instance_) { 11 | T *t = new T; 12 | T *n = nullptr; 13 | if (!instance_.compare_exchange_weak(n, t)) 14 | delete t; 15 | } 16 | return *instance_; 17 | } 18 | 19 | template 20 | void 21 | Singleton::release() 22 | { 23 | T *t = instance_; 24 | if (instance_.compare_exchange_strong(t, nullptr)) 25 | delete t; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mimosa/smtp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | client.hh 3 | mail.hh 4 | DESTINATION include/mimosa/smtp/) 5 | 6 | add_library(mimosa-smtp STATIC 7 | client.cc 8 | mail.cc) 9 | target_link_libraries(mimosa-smtp PUBLIC mimosa) 10 | 11 | install(TARGETS mimosa-smtp 12 | RUNTIME DESTINATION bin 13 | LIBRARY DESTINATION lib 14 | ARCHIVE DESTINATION lib) 15 | 16 | add_subdirectory(sample) 17 | -------------------------------------------------------------------------------- /mimosa/smtp/client.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../non-copyable.hh" 4 | # include "../stream/net-fd-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace smtp 9 | { 10 | struct Mail; 11 | 12 | /** 13 | * Simple smtp client. 14 | * https://tools.ietf.org/html/rfc5321 15 | */ 16 | class Client : private NonCopyable 17 | { 18 | public: 19 | Client(); 20 | 21 | bool connect(const std::string & host, uint16_t port); 22 | bool hello(const std::string & name); 23 | bool from(const std::string & name); 24 | bool to(const std::string & name); 25 | bool data(const std::string & data); 26 | void quit(); 27 | void close(); 28 | 29 | bool sendMail(const Mail & mail); 30 | 31 | private: 32 | stream::NetFdStream::Ptr stream_; 33 | // stream::BufferedStream::Ptr stream_; 34 | }; 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /mimosa/smtp/mail.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "mail.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace smtp 8 | { 9 | std::string 10 | Mail::data() const 11 | { 12 | std::ostringstream os; 13 | os << "From: " << from << "\r\n"; 14 | 15 | bool first = true; 16 | for (auto & it : to) { 17 | if (first) 18 | os << "To: "; 19 | else 20 | os << ", "; 21 | os << it; 22 | first = false; 23 | } 24 | if (!first) 25 | os << "\r\n"; 26 | 27 | first = true; 28 | for (auto & it : cc) { 29 | if (first) 30 | os << "Cc: "; 31 | else 32 | os << ", "; 33 | os << it; 34 | first = false; 35 | } 36 | if (!first) 37 | os << "\r\n"; 38 | 39 | os << "Date: " << date << "\r\n"; 40 | os << "Subject: " << subject << "\r\n"; 41 | os << "\r\n"; 42 | os << content; 43 | 44 | return os.str(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mimosa/smtp/mail.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | namespace mimosa 7 | { 8 | namespace smtp 9 | { 10 | struct Mail 11 | { 12 | std::string data() const; 13 | 14 | std::vector to; 15 | std::vector cc; 16 | std::vector bcc; 17 | std::string from; 18 | std::string reply_to; 19 | std::string subject; 20 | std::string date; 21 | std::string content; 22 | }; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/smtp/sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(msendmail msendmail.cc) 2 | target_link_libraries(msendmail mimosa-smtp) -------------------------------------------------------------------------------- /mimosa/smtp/sample/msendmail.cc: -------------------------------------------------------------------------------- 1 | #include "../../init.hh" 2 | #include "../..//options/options.hh" 3 | 4 | #include "../mail.hh" 5 | #include "../client.hh" 6 | 7 | std::string & HOST = *mimosa::options::addOption("", "host", "", ""); 8 | std::string & TO = *mimosa::options::addOption("", "to", "", ""); 9 | std::string & FROM = *mimosa::options::addOption("", "from", "", ""); 10 | std::string & SUBJECT = *mimosa::options::addOption("", "subject", "", ""); 11 | std::string & DATE = *mimosa::options::addOption("", "date", "", ""); 12 | std::string & CONTENT = *mimosa::options::addOption("", "content", "", ""); 13 | 14 | int main(int argc, char **argv) 15 | { 16 | mimosa::init(argc, argv); 17 | 18 | mimosa::smtp::Client client; 19 | if (!client.connect(HOST, 25)) 20 | return 1; 21 | 22 | if (!client.hello("localhost")) 23 | return 2; 24 | 25 | mimosa::smtp::Mail mail; 26 | mail.to.push_back(TO); 27 | mail.from = FROM; 28 | mail.subject = SUBJECT; 29 | mail.date = DATE; 30 | mail.content = CONTENT; 31 | 32 | if (!client.sendMail(mail)) 33 | return 3; 34 | 35 | mimosa::deinit(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /mimosa/spin-lock.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "non-copyable.hh" 6 | #include "locker.hh" 7 | #include "unique-locker.hh" 8 | 9 | namespace mimosa 10 | { 11 | /** 12 | * SpinLock is a user level lock which will actively loop until it can 13 | * acquire the lock. 14 | * 15 | * @warning don't use it in situation where the lock ownership is longer 16 | * than 50us (mode switch). 17 | * 18 | * @ingroup Sync 19 | */ 20 | class SpinLock : private NonCopyable 21 | { 22 | public: 23 | typedef mimosa::Locker Locker; 24 | typedef mimosa::UniqueLocker UniqueLocker; 25 | 26 | SpinLock() noexcept = default; 27 | inline ~SpinLock() noexcept; 28 | inline void lock() noexcept; 29 | inline bool tryLock() noexcept; 30 | inline void unlock() noexcept; 31 | 32 | private: 33 | int lock_ = 0; 34 | }; 35 | } 36 | 37 | #include "spin-lock.hxx" 38 | -------------------------------------------------------------------------------- /mimosa/spin-lock.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mimosa 4 | { 5 | inline 6 | SpinLock::~SpinLock() noexcept 7 | { 8 | /* wait for unlock */ 9 | while (lock_) 10 | ; 11 | } 12 | 13 | inline void 14 | SpinLock::lock() noexcept 15 | { 16 | while (!__sync_bool_compare_and_swap(&lock_, 0, 1)) 17 | ; 18 | } 19 | 20 | inline bool 21 | SpinLock::tryLock() noexcept 22 | { 23 | return __sync_bool_compare_and_swap(&lock_, 0, 1); 24 | } 25 | 26 | inline void 27 | SpinLock::unlock() noexcept 28 | { 29 | lock_ = 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mimosa/sqlite/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | sqlite.hh 3 | sqlite.hxx 4 | DESTINATION include/mimosa/sqlite) 5 | 6 | add_library(mimosa-sqlite STATIC sqlite.cc) 7 | target_link_libraries(mimosa-sqlite PUBLIC mimosa) 8 | 9 | install(TARGETS mimosa-sqlite 10 | RUNTIME DESTINATION bin 11 | LIBRARY DESTINATION lib 12 | ARCHIVE DESTINATION lib) 13 | -------------------------------------------------------------------------------- /mimosa/stream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | base16-decoder.hh 3 | base16-encoder.hh 4 | base64-decoder.hh 5 | buffered-stream.hh 6 | buffer.hh 7 | copy.hh 8 | direct-fd-stream.hh 9 | fd-stream.hh 10 | filter.hh 11 | filter.hxx 12 | hash.hh 13 | html-escape.hh 14 | limited-stream.hh 15 | lzma.hh 16 | lzma-decoder.hh 17 | lzma-encoder.hh 18 | net-fd-stream.hh 19 | percent-encoder.hh 20 | stream.hh 21 | string-stream.hh 22 | tee-stream.hh 23 | tls-stream.hh 24 | zlib-encoder.hh 25 | DESTINATION include/mimosa/stream/) 26 | 27 | add_subdirectory(tests) 28 | -------------------------------------------------------------------------------- /mimosa/stream/base16-decoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "filter.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class Base16Decoder : public Filter 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(Base16Decoder); 13 | 14 | explicit Base16Decoder(Stream::Ptr stream, const char * base = nullptr); 15 | 16 | virtual int64_t write(const char * data, uint64_t nbytes); 17 | virtual int64_t read(char * data, uint64_t nbytes); 18 | 19 | uint8_t decodeByte(uint8_t c) const; 20 | 21 | private: 22 | const char * base_; 23 | }; 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /mimosa/stream/base16-encoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "filter.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class Base16Encoder : public Filter 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(Base16Encoder); 13 | 14 | explicit Base16Encoder(Stream::Ptr stream, bool upper = false); 15 | Base16Encoder(Stream::Ptr stream, const char * base); 16 | 17 | virtual int64_t write(const char * data, uint64_t nbytes); 18 | virtual int64_t read(char * data, uint64_t nbytes); 19 | 20 | static int64_t write(Stream::Ptr stream, const char *data, uint64_t nbytes, bool upper = false); 21 | 22 | private: 23 | const char * base_; 24 | }; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mimosa/stream/base64-decoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "filter.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class Base64Decoder : public Filter 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(Base64Decoder); 13 | 14 | explicit Base64Decoder(Stream::Ptr stream, const char * base = nullptr); 15 | 16 | virtual int64_t write(const char * data, uint64_t nbytes); 17 | virtual int64_t read(char * data, uint64_t nbytes); 18 | 19 | uint8_t decodeByte(uint8_t c) const; 20 | 21 | private: 22 | const char * base_; 23 | uint8_t buff_[4]; 24 | size_t off_; 25 | uint8_t pad_; 26 | }; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/stream/buffer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "buffer.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace stream 9 | { 10 | Buffer::Buffer(uint64_t size) 11 | : next_(), 12 | size_(size), 13 | data_(reinterpret_cast(::malloc(size + 4))) 14 | { 15 | data_[size_ + 3] = 0; 16 | data_[size_ + 2] = 0; 17 | data_[size_ + 1] = 0; 18 | data_[size_] = 0; 19 | } 20 | 21 | Buffer::Buffer(const char * data, uint64_t size) 22 | : next_(), 23 | size_(size), 24 | data_(reinterpret_cast(::malloc(size + 4))) 25 | { 26 | ::memcpy(data_, data, size); 27 | data_[size_ + 3] = 0; 28 | data_[size_ + 2] = 0; 29 | data_[size_ + 1] = 0; 30 | data_[size_] = 0; 31 | } 32 | 33 | Buffer::~Buffer() 34 | { 35 | free(data_); 36 | size_ = 0; 37 | data_ = nullptr; 38 | } 39 | 40 | void 41 | Buffer::resize(uint64_t size) 42 | { 43 | data_ = reinterpret_cast(::realloc(data_, size + 4)); 44 | size_ = size; 45 | data_[size_ + 3] = 0; 46 | data_[size_ + 2] = 0; 47 | data_[size_ + 1] = 0; 48 | data_[size_] = 0; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /mimosa/stream/buffer.hh: -------------------------------------------------------------------------------- 1 | #ifndef MIMOSA_STREAM_BUFFER_HH 2 | # define MIMOSA_STREAM_BUFFER_HH 3 | 4 | # include 5 | 6 | # include "../ref-countable.hh" 7 | # include "../intrusive-slist.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace stream 12 | { 13 | /** 14 | * @todo copy constructor, move constructor, operator= 15 | * @info the real size of the buffer is size + 4. So it's null terminated 16 | * and you can pass the buffer to flex without duplicating it. 17 | */ 18 | class Buffer : public RefCountable, private NonCopyable, private NonMovable 19 | { 20 | public: 21 | explicit Buffer(uint64_t size = 64 * 1024); 22 | /** constructs a copy of the data buffer */ 23 | Buffer(const char * data, uint64_t size); 24 | ~Buffer(); 25 | 26 | inline uint64_t size() const { return size_; } 27 | inline char * data() { return data_; } 28 | inline const char * data() const { return data_; } 29 | void resize(uint64_t size); 30 | 31 | private: 32 | IntrusiveSlistHook next_; 33 | uint64_t size_; 34 | char * data_; 35 | 36 | public: 37 | typedef IntrusiveSlist Slist; 38 | friend class IntrusiveSlist; 39 | }; 40 | } 41 | } 42 | 43 | #endif /* !MIMOSA_STREAM_BUFFER_HH */ 44 | -------------------------------------------------------------------------------- /mimosa/stream/copy.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "buffer.hh" 6 | #include "copy.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace stream 11 | { 12 | int64_t copy(Stream & input, 13 | Stream & output, 14 | const int64_t max_bytes) 15 | { 16 | stream::Buffer::Ptr buffer = new stream::Buffer; 17 | int64_t copied_bytes = 0; 18 | while (true) 19 | { 20 | int64_t to_do = buffer->size(); 21 | 22 | // compute the number of bytes to read/write 23 | if (max_bytes > 0 && max_bytes - copied_bytes < to_do) 24 | to_do = max_bytes - copied_bytes; 25 | 26 | int64_t rbytes = input.read(buffer->data(), to_do); 27 | if (rbytes <= 0) 28 | return copied_bytes; 29 | 30 | int64_t wbytes = output.loopWrite(buffer->data(), rbytes); 31 | if (wbytes != rbytes) 32 | return -1; 33 | 34 | copied_bytes += wbytes; 35 | } 36 | return copied_bytes; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mimosa/stream/copy.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "stream.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | int64_t copy(Stream & input, 10 | Stream & output, 11 | int64_t max_bytes = 0); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /mimosa/stream/direct-fd-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | # include 6 | # include 7 | 8 | # include "stream.hh" 9 | 10 | namespace mimosa 11 | { 12 | namespace stream 13 | { 14 | class DirectFdStream : public Stream 15 | { 16 | public: 17 | MIMOSA_DEF_PTR(DirectFdStream); 18 | 19 | explicit DirectFdStream(int fd = -1, bool own_fd = true); 20 | virtual ~DirectFdStream(); 21 | 22 | virtual int64_t write(const char * data, uint64_t nbytes); 23 | virtual int64_t writev(const struct iovec *iov, int iovcnt); 24 | virtual int64_t read(char * data, uint64_t nbytes); 25 | virtual int64_t readv(const struct iovec *iov, int iovcnt); 26 | 27 | virtual void close(); 28 | 29 | bool open(const char * path, int oflags = O_RDONLY, mode_t mode = 0644); 30 | int fd() const { return fd_; } 31 | ::mode_t fdMode() const { if (!mode_) stat(); return mode_; } 32 | bool stat() const; 33 | 34 | protected: 35 | int fd_; 36 | bool own_fd_; 37 | mutable ::mode_t mode_; // st_mode from struct ::stat 38 | }; 39 | 40 | int64_t copy(DirectFdStream & input, 41 | DirectFdStream & output, 42 | int64_t max_bytes = 0); 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /mimosa/stream/fd-stream.cc: -------------------------------------------------------------------------------- 1 | #include "fd-stream.hh" 2 | #include "direct-fd-stream.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace stream 7 | { 8 | FdStream::FdStream(int fd, uint64_t buffer_size, bool own_fd) 9 | : BufferedStream(new DirectFdStream(fd, own_fd), buffer_size) 10 | { 11 | } 12 | 13 | FdStream::FdStream(const DirectFdStream::Ptr& stream, uint64_t buffer_size) 14 | : BufferedStream(stream.get(), buffer_size) 15 | { 16 | } 17 | 18 | FdStream::Ptr 19 | FdStream::openFile(const char * path, int oflags, mode_t mode) 20 | { 21 | int fd = ::open(path, oflags, mode); 22 | if (fd < 0) 23 | return nullptr; 24 | 25 | auto stream = new DirectFdStream(fd, true); 26 | return new FdStream(stream); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mimosa/stream/fd-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "buffered-stream.hh" 4 | # include "direct-fd-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace stream 9 | { 10 | class FdStream : public BufferedStream 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(FdStream); 14 | 15 | explicit FdStream(int fd, uint64_t buffer_size = 64 * 1024, bool own_fd = true); 16 | explicit FdStream(const DirectFdStream::Ptr& stream, uint64_t buffer_size = 64 * 1024); 17 | 18 | static FdStream::Ptr openFile(const char * path, int oflags = O_RDONLY, mode_t mode = 0644); 19 | }; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /mimosa/stream/filter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "filter.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace stream 10 | { 11 | Filter::Filter(Stream::Ptr stream) 12 | : stream_(std::move(std::move(stream))) 13 | { 14 | } 15 | 16 | bool 17 | Filter::flush() 18 | { 19 | return stream_->flush(); 20 | } 21 | 22 | void 23 | Filter::setReadTimeout(Time timeout) 24 | { 25 | stream_->setReadTimeout(timeout); 26 | } 27 | 28 | void 29 | Filter::setWriteTimeout(Time timeout) 30 | { 31 | stream_->setWriteTimeout(timeout); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mimosa/stream/filter.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "stream.hh" 7 | 8 | namespace mimosa { namespace stream { 9 | class Filter : public Stream { 10 | public: 11 | MIMOSA_DEF_PTR(Filter); 12 | 13 | explicit Filter(Stream::Ptr stream); 14 | 15 | virtual int64_t write(const char *data, uint64_t nbytes) = 0; 16 | virtual int64_t read(char *data, uint64_t nbytes) = 0; 17 | 18 | virtual bool flush(); 19 | virtual void setReadTimeout(Time timeout); 20 | virtual void setWriteTimeout(Time timeout); 21 | 22 | protected: 23 | Stream::Ptr stream_; 24 | }; 25 | 26 | template 27 | inline std::string filter(const std::string &data); 28 | 29 | template 30 | inline std::string filter(const std::string_view &data); 31 | 32 | template 33 | inline std::string filter(const char *data, uint64_t nbytes); 34 | }} // namespace mimosa::stream 35 | 36 | #include "filter.hxx" 37 | -------------------------------------------------------------------------------- /mimosa/stream/filter.hxx: -------------------------------------------------------------------------------- 1 | #include "string-stream.hh" 2 | 3 | namespace mimosa { namespace stream { 4 | template 5 | inline std::string filter(const char *data, uint64_t nbytes) { 6 | mimosa::stream::StringStream::Ptr s = new mimosa::stream::StringStream; 7 | T filter(s.get()); 8 | filter.write(data, nbytes); 9 | return s->moveStr(); 10 | } 11 | 12 | template 13 | inline std::string filter(const std::string &data) { 14 | return filter(data.data(), data.size()); 15 | } 16 | 17 | template 18 | inline std::string filter(const std::string_view &data) { 19 | return filter(data.data(), data.size()); 20 | } 21 | }} // namespace mimosa::stream 22 | -------------------------------------------------------------------------------- /mimosa/stream/html-escape.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "filter.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class HtmlEscape : public Filter 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(HtmlEscape); 13 | 14 | explicit HtmlEscape(Stream::Ptr stream); 15 | 16 | virtual int64_t write(const char * data, uint64_t nbytes); 17 | virtual int64_t read(char * data, uint64_t nbytes); 18 | }; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /mimosa/stream/limited-stream.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "limited-stream.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace stream 11 | { 12 | LimitedStream::LimitedStream(Stream::Ptr stream) 13 | : stream_(std::move(std::move(stream))), 14 | rbytes_left_(0), 15 | wbytes_left_(0) 16 | { 17 | } 18 | 19 | int64_t 20 | LimitedStream::write(const char * data, uint64_t nbytes) 21 | { 22 | uint64_t can_write = std::min(nbytes, wbytes_left_); 23 | if (can_write == 0) 24 | return 0; 25 | 26 | int64_t wbytes = stream_->write(data, can_write); 27 | if (wbytes > 0) 28 | wbytes_left_ -= wbytes; 29 | return wbytes; 30 | } 31 | 32 | int64_t 33 | LimitedStream::read(char * data, uint64_t nbytes) 34 | { 35 | uint64_t can_read = std::min(nbytes, rbytes_left_); 36 | if (can_read == 0) 37 | return 0; 38 | 39 | int64_t rbytes = stream_->read(data, can_read); 40 | if (rbytes > 0) 41 | rbytes_left_ -= rbytes; 42 | return rbytes; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mimosa/stream/limited-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "stream.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class LimitedStream : public Stream 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(LimitedStream); 13 | 14 | explicit LimitedStream(Stream::Ptr stream); 15 | 16 | virtual int64_t write(const char * data, uint64_t nbytes); 17 | virtual int64_t read(char * data, uint64_t nbytes); 18 | 19 | inline void setReadLimit(uint64_t bytes) { rbytes_left_ = bytes; } 20 | inline void setWriteLimit(uint64_t bytes) { wbytes_left_ = bytes; } 21 | 22 | private: 23 | Stream::Ptr stream_; 24 | uint64_t rbytes_left_; 25 | uint64_t wbytes_left_; 26 | }; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/stream/lzma-decoder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lzma-decoder.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | LzmaDecoder::LzmaDecoder(Stream::Ptr stream, uint64_t memlimit, uint32_t flags) 10 | : Lzma(std::move(stream)) 11 | { 12 | if (lzma_auto_decoder(&lzma_, memlimit, flags) != LZMA_OK) 13 | assert(false); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mimosa/stream/lzma-decoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "lzma.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class LzmaDecoder : public Lzma 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(LzmaDecoder); 13 | 14 | explicit LzmaDecoder(Stream::Ptr stream, 15 | uint64_t memlimit = UINT64_MAX, 16 | uint32_t flags = 0); 17 | }; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /mimosa/stream/lzma-encoder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lzma-encoder.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | LzmaEncoder::LzmaEncoder(Stream::Ptr stream, uint32_t preset, lzma_check check) 10 | : Lzma(std::move(stream)) 11 | { 12 | if (lzma_easy_encoder(&lzma_, preset, check) != LZMA_OK) 13 | assert(false); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mimosa/stream/lzma-encoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "lzma.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class LzmaEncoder : public Lzma 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(LzmaEncoder); 13 | 14 | explicit LzmaEncoder(Stream::Ptr stream, 15 | uint32_t preset = 5, 16 | lzma_check check = LZMA_CHECK_CRC64); 17 | }; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /mimosa/stream/lzma.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "buffer.hh" 6 | # include "filter.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace stream 11 | { 12 | class Lzma : public Filter 13 | { 14 | public: 15 | MIMOSA_DEF_PTR(Lzma); 16 | 17 | virtual ~Lzma(); 18 | 19 | virtual int64_t write(const char * data, uint64_t nbytes); 20 | virtual int64_t read(char * data, uint64_t nbytes); 21 | 22 | virtual bool flush(); 23 | 24 | protected: 25 | explicit Lzma(Stream::Ptr stream); 26 | 27 | lzma_stream lzma_; 28 | Buffer buffer_; 29 | }; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /mimosa/stream/net-fd-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "direct-fd-stream.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | class NetFdStream : public DirectFdStream 10 | { 11 | public: 12 | MIMOSA_DEF_PTR(NetFdStream); 13 | 14 | explicit NetFdStream(int fd, bool own_fd = true); 15 | 16 | virtual int64_t write(const char * data, uint64_t nbytes) override; 17 | virtual int64_t writev(const struct iovec *iov, int iovcnt) override; 18 | virtual int64_t read(char * data, uint64_t nbytes) override; 19 | virtual int64_t readv(const struct iovec *iov, int iovcnt) override; 20 | 21 | virtual void setReadTimeout(Time timeout) override; 22 | virtual void setWriteTimeout(Time timeout) override; 23 | 24 | virtual void setReadIdleTimeout(Time timeout) override; 25 | virtual void setWriteIdleTimeout(Time timeout) override; 26 | 27 | void shutdownInput() override; 28 | void shutdownOutput() override; 29 | void shutdown() override; 30 | 31 | private: 32 | Time read_timeout_; 33 | Time write_timeout_; 34 | Time read_idle_timeout_; 35 | Time write_idle_timeout_; 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mimosa/stream/percent-encoder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "percent-encoder.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace stream 9 | { 10 | PercentEncoder::PercentEncoder(Stream::Ptr stream, 11 | uri::EncodingType enc) 12 | : Filter(std::move(stream)), 13 | enc_(enc) 14 | { 15 | } 16 | 17 | int64_t 18 | PercentEncoder::write(const char * data, uint64_t nbytes) 19 | { 20 | std::string out; 21 | 22 | uri::percentEncode(data, nbytes, &out, enc_); 23 | if (stream_->loopWrite(out.data(), out.size()) == static_cast (out.size())) 24 | return nbytes; 25 | return -1; 26 | } 27 | 28 | int64_t 29 | PercentEncoder::read(char * /*data*/, uint64_t /*nbytes*/) 30 | { 31 | assert(false && "NOT IMPLEMENTED"); 32 | errno = ENOSYS; 33 | return -1; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/stream/percent-encoder.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "filter.hh" 4 | # include "../uri/percent-encoding.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace stream 9 | { 10 | class PercentEncoder : public Filter 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(PercentEncoder); 14 | 15 | explicit PercentEncoder(Stream::Ptr stream, uri::EncodingType enc = uri::kRfc3986); 16 | 17 | virtual int64_t write(const char * data, uint64_t nbytes); 18 | virtual int64_t read(char * data, uint64_t nbytes); 19 | 20 | protected: 21 | uri::EncodingType enc_; 22 | }; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mimosa/stream/string-stream.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "string-stream.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace stream 9 | { 10 | StringStream::StringStream(std::string str) 11 | : read_pos_(0), 12 | str_(std::move(str)) 13 | { 14 | } 15 | 16 | int64_t 17 | StringStream::write(const char * data, uint64_t nbytes) 18 | { 19 | str_.append(data, nbytes); 20 | return nbytes; 21 | } 22 | 23 | int64_t 24 | StringStream::read(char * data, uint64_t nbytes) 25 | { 26 | if (str_.size() <= read_pos_) 27 | return 0; 28 | 29 | int64_t can_read = std::min( 30 | nbytes, static_cast (str_.size() - read_pos_)); 31 | ::memcpy(data, str_.data() + read_pos_, can_read); 32 | read_pos_ += can_read; 33 | return can_read; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/stream/string-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "stream.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace stream 10 | { 11 | class StringStream : public Stream 12 | { 13 | public: 14 | MIMOSA_DEF_PTR(StringStream); 15 | 16 | explicit StringStream(std::string str = ""); 17 | 18 | virtual int64_t write(const char * data, uint64_t nbytes); 19 | virtual int64_t read(char * data, uint64_t nbytes); 20 | 21 | inline const std::string & str() const { return str_; } 22 | inline std::string && moveStr() { read_pos_ = 0; return std::move(str_); } 23 | inline void setStr(const std::string & str) 24 | { 25 | read_pos_ = 0; 26 | str_ = str; 27 | } 28 | inline void setStr(std::string && str) 29 | { 30 | read_pos_ = 0; 31 | str_ = str; 32 | } 33 | 34 | inline void clear() { read_pos_ = 0; str_.clear(); } 35 | 36 | private: 37 | std::string::size_type read_pos_; 38 | std::string str_; 39 | }; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /mimosa/stream/tee-stream.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "tee-stream.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace stream 10 | { 11 | TeeStream::TeeStream(Stream::Ptr stream) 12 | : stream_(std::move(std::move(stream))) 13 | { 14 | } 15 | 16 | int64_t 17 | TeeStream::write(const char * data, uint64_t nbytes) 18 | { 19 | auto bytes = stream_->write(data, nbytes); 20 | if (bytes < 0) 21 | return bytes; 22 | for (auto & ostream : ostreams_) 23 | ostream->write(data, bytes); 24 | return bytes; 25 | } 26 | 27 | int64_t 28 | TeeStream::read(char * data, uint64_t nbytes) 29 | { 30 | auto bytes = stream_->read(data, nbytes); 31 | if (bytes < 0) 32 | return bytes; 33 | for (auto & istream : istreams_) 34 | istream->write(data, bytes); 35 | return bytes; 36 | } 37 | 38 | void 39 | TeeStream::close() 40 | { 41 | stream_->close(); 42 | for (auto & istream : istreams_) 43 | istream->close(); 44 | for (auto & ostream : ostreams_) 45 | ostream->close(); 46 | } 47 | 48 | bool 49 | TeeStream::flush() 50 | { 51 | auto ret = stream_->flush(); 52 | for (auto & istream : istreams_) 53 | istream->flush(); 54 | for (auto & ostream : ostreams_) 55 | ostream->flush(); 56 | return ret; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mimosa/stream/tee-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "stream.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace stream 10 | { 11 | /** 12 | * TeeStream is mainly used for debug purpose. 13 | * It copies everything wrote to ostreams_ and 14 | * everything read to istreams_. 15 | */ 16 | class TeeStream : public Stream 17 | { 18 | public: 19 | MIMOSA_DEF_PTR(TeeStream); 20 | 21 | explicit TeeStream(Stream::Ptr stream); 22 | 23 | inline void teeOutput(Stream::Ptr stream) { ostreams_.push_back(stream); } 24 | inline void teeInput(Stream::Ptr stream) { istreams_.push_back(stream); } 25 | 26 | virtual int64_t write(const char * data, uint64_t nbytes); 27 | virtual int64_t read(char * data, uint64_t nbytes); 28 | 29 | virtual void close(); 30 | virtual bool flush(); 31 | 32 | Stream::Ptr stream_; 33 | std::vector ostreams_; 34 | std::vector istreams_; 35 | }; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /mimosa/stream/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa-stream 2 | tst-filters.cc 3 | tst-hash.cc 4 | tst-html-escape.cc) 5 | 6 | add_executable(lzma-encoder EXCLUDE_FROM_ALL lzma-encoder.cc) 7 | target_link_libraries(lzma-encoder mimosa lzma) 8 | 9 | add_executable(lzma-decoder EXCLUDE_FROM_ALL lzma-decoder.cc) 10 | target_link_libraries(lzma-decoder mimosa lzma) 11 | -------------------------------------------------------------------------------- /mimosa/stream/tests/lzma-decoder.cc: -------------------------------------------------------------------------------- 1 | #include "../copy.hh" 2 | #include "../fd-stream.hh" 3 | #include "../lzma-decoder.hh" 4 | 5 | int main(int argc, char **argv) 6 | { 7 | mimosa::stream::Stream::Ptr in = new mimosa::stream::FdStream(0); 8 | mimosa::stream::Stream::Ptr out = new mimosa::stream::FdStream(1); 9 | mimosa::stream::Stream::Ptr lzma = new mimosa::stream::LzmaDecoder(out); 10 | 11 | mimosa::stream::copy(*in, *lzma); 12 | lzma->flush(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /mimosa/stream/tests/lzma-encoder.cc: -------------------------------------------------------------------------------- 1 | #include "../copy.hh" 2 | #include "../fd-stream.hh" 3 | #include "../lzma-encoder.hh" 4 | 5 | int main(int argc, char **argv) 6 | { 7 | mimosa::stream::Stream::Ptr in = new mimosa::stream::FdStream(0); 8 | mimosa::stream::Stream::Ptr out = new mimosa::stream::FdStream(1); 9 | mimosa::stream::Stream::Ptr lzma = new mimosa::stream::LzmaEncoder(out); 10 | 11 | mimosa::stream::copy(*in, *lzma); 12 | lzma->flush(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /mimosa/stream/tests/tst-filters.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../string-stream.hh" 4 | #include "../base16-encoder.hh" 5 | #include "../base16-decoder.hh" 6 | #include "../base64-decoder.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace stream 11 | { 12 | namespace 13 | { 14 | #define TOKENPASTE(x, y) x ## y 15 | #define TOKENPASTE2(x, y) TOKENPASTE(x, y) 16 | 17 | #define FILTER_TEST(Type, Input, Output) \ 18 | TEST(Type, TOKENPASTE2(Simple, __LINE__)) \ 19 | { \ 20 | StringStream::Ptr str = new StringStream; \ 21 | Type::Ptr filter = new Type(str.get()); \ 22 | filter->write(Input, sizeof (Input) - 1); \ 23 | ASSERT_EQ(str->str(), Output); \ 24 | } 25 | 26 | FILTER_TEST(Base16Encoder, "bonjour", "626f6e6a6f7572") 27 | FILTER_TEST(Base16Decoder, "626f6e6a6f7572", "bonjour") 28 | 29 | FILTER_TEST(Base64Decoder, "cGxlYXN1cmUu", "pleasure.") 30 | FILTER_TEST(Base64Decoder, "bGVhc3VyZS4=", "leasure.") 31 | FILTER_TEST(Base64Decoder, "ZWFzdXJlLg==", "easure.") 32 | FILTER_TEST(Base64Decoder, "YXN1cmUu", "asure.") 33 | FILTER_TEST(Base64Decoder, "c3VyZS4=", "sure.") 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/stream/tests/tst-html-escape.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../string-stream.hh" 3 | #include "../html-escape.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace stream 8 | { 9 | namespace 10 | { 11 | 12 | #define MY_TEST(Test, Input, Output) \ 13 | TEST(HtmlEscape, Test) \ 14 | { \ 15 | StringStream::Ptr stream = new StringStream; \ 16 | HtmlEscape::Ptr filter = new HtmlEscape(stream.get()); \ 17 | filter->loopWrite(Input, sizeof (Input) - 1); \ 18 | ASSERT_EQ(Output, stream->str()); \ 19 | } 20 | 21 | MY_TEST(gt, ">", ">") 22 | MY_TEST(lt, "<", "<") 23 | MY_TEST(amp, "&", "&") 24 | MY_TEST(apos, "'", "'") 25 | MY_TEST(quot, "\"", """) 26 | 27 | MY_TEST(empty, "", "") 28 | MY_TEST(clean, "abcdef", "abcdef") 29 | MY_TEST(mixed1, "ab&", "ab&") 30 | MY_TEST(mixed2, "&ab", "&ab") 31 | MY_TEST(mixed3, "ab&ab", "ab&ab") 32 | MY_TEST(mixed4, "ab&&&cd", "ab&&&cd") 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/stream/tls-stream.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "filter.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace stream 10 | { 11 | class TlsStream : public Filter 12 | { 13 | public: 14 | MIMOSA_DEF_PTR(TlsStream); 15 | 16 | TlsStream(Stream::Ptr stream, bool is_server); 17 | ~TlsStream(); 18 | 19 | virtual int64_t write(const char * data, uint64_t nbytes); 20 | virtual int64_t read(char * data, uint64_t nbytes); 21 | 22 | virtual void close(); 23 | 24 | inline gnutls_session_t session() { return session_; } 25 | 26 | private: 27 | static ssize_t readWrapper(TlsStream * stream, char * data, size_t nbytes); 28 | static ssize_t writeWrapper(TlsStream * stream, const char * data, size_t nbytes); 29 | static ssize_t writevWrapper(TlsStream * stream, const giovec_t * iov, int iovcnt); 30 | 31 | gnutls_session_t session_; 32 | }; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /mimosa/string/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | string-ref.hh 3 | DESTINATION include/mimosa/string/) 4 | 5 | add_subdirectory(tests) 6 | -------------------------------------------------------------------------------- /mimosa/string/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa-string tst-string-ref.cc) 2 | -------------------------------------------------------------------------------- /mimosa/sync.doch: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @defgroup Sync Synchronization 4 | 5 | */ 6 | -------------------------------------------------------------------------------- /mimosa/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | mimosa_test(mimosa 2 | 3 | # containers 4 | tst-cache.cc 5 | tst-intrusive-dlist.cc 6 | tst-intrusive-hash-table.cc 7 | tst-trie.cc 8 | 9 | tst-ref-countable.cc 10 | tst-string-ref.cc 11 | tst-container-of.cc 12 | ) 13 | -------------------------------------------------------------------------------- /mimosa/tests/tst-cache.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../expiring-cache.hh" 4 | #include "../expiring-cache.hxx" 5 | 6 | namespace mimosa 7 | { 8 | namespace 9 | { 10 | class MyCache : public ExpiringCache 11 | { 12 | protected: 13 | virtual void cacheMiss(const int & key) 14 | { 15 | set(key, key + 42); 16 | } 17 | }; 18 | 19 | TEST(ExpiringCache, Simple) 20 | { 21 | MyCache cache; 22 | 23 | auto val = cache.get(0); 24 | ASSERT_EQ(val->get(), 42); 25 | 26 | val = cache.get(0); 27 | ASSERT_EQ(val->get(), 42); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /mimosa/tests/tst-container-of.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../container-of.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace tests 8 | { 9 | namespace 10 | { 11 | struct A 12 | { 13 | int dummy; 14 | }; 15 | 16 | struct B 17 | { 18 | A bibi; 19 | char tutu[128]; 20 | A tata; 21 | char toto[64]; 22 | A tetons; 23 | }; 24 | 25 | TEST(ContainerOf, Simple) 26 | { 27 | B b; 28 | A * a; 29 | B * b2; 30 | 31 | a = &b.bibi; 32 | b2 = containerOf(a, &B::bibi); 33 | EXPECT_EQ(&b, b2); 34 | 35 | a = &b.tata; 36 | b2 = containerOf(a, &B::tata); 37 | EXPECT_EQ(&b, b2); 38 | 39 | a = &b.tetons; 40 | b2 = containerOf(a, &B::tetons); 41 | EXPECT_EQ(&b, b2); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mimosa/tests/tst-ref-countable.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../ref-countable.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace 8 | { 9 | struct A : public RefCountable 10 | { 11 | int v; 12 | }; 13 | 14 | TEST(RefCountable, Simple) 15 | { 16 | A::Ptr obj = new A; 17 | obj = nullptr; 18 | } 19 | 20 | TEST(RefCountable, SimplePtr) 21 | { 22 | A::Ptr obj = new A; 23 | A::Ptr obj2(obj.get()); 24 | } 25 | 26 | TEST(RefCountable, Assign) 27 | { 28 | A::Ptr obj = new A; 29 | A::Ptr obj2; 30 | 31 | obj2 = nullptr; 32 | obj2 = obj; 33 | obj2 = nullptr; 34 | obj2 = obj; 35 | } 36 | 37 | TEST(RefCountable, CopyConstructor) 38 | { 39 | A::Ptr obj = new A; 40 | const A::Ptr& obj2(obj); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mimosa/thread-pool.cc: -------------------------------------------------------------------------------- 1 | #include "thread-pool.hh" 2 | 3 | namespace mimosa 4 | { 5 | ThreadPool::ThreadPool(std::function && fct) 6 | : fct_(std::make_unique>(std::move(fct))) 7 | { 8 | } 9 | 10 | ThreadPool::~ThreadPool() 11 | { 12 | join(); 13 | } 14 | 15 | bool 16 | ThreadPool::startThread() 17 | { 18 | return startThread(std::function (*fct_)); 19 | } 20 | 21 | bool 22 | ThreadPool::startThread(std::function && fct) 23 | { 24 | Thread t; 25 | if (!t.start(std::move(fct))) 26 | return false; 27 | 28 | threads_.emplace_back(std::move(t)); 29 | return true; 30 | } 31 | 32 | void 33 | ThreadPool::join() 34 | { 35 | for (auto & thread : threads_) 36 | thread.join(); 37 | threads_.clear(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mimosa/thread-pool.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "thread.hh" 7 | 8 | namespace mimosa 9 | { 10 | class ThreadPool 11 | { 12 | public: 13 | explicit ThreadPool(std::function && fct); 14 | ~ThreadPool(); 15 | 16 | inline ThreadPool & setStackSize(uint32_t size) { stack_size_ = size; return *this; } 17 | 18 | bool startThread(); 19 | inline uint32_t startThreads(uint32_t nb) { 20 | for (uint32_t i = 0; i < nb; ++i) 21 | if (!startThread()) 22 | return i; 23 | return nb; 24 | } 25 | 26 | bool startThread(std::function && fct); 27 | 28 | void join(); 29 | 30 | private: 31 | uint32_t stack_size_ = 128 * 1024; 32 | std::vector threads_; 33 | std::unique_ptr> fct_; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /mimosa/thread.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "non-copyable.hh" 9 | #include "non-movable.hh" 10 | #include "time.hh" 11 | 12 | namespace mimosa 13 | { 14 | class Thread 15 | { 16 | public: 17 | constexpr Thread() = default; 18 | Thread(const Thread& other) = delete; 19 | Thread(Thread && other) noexcept; 20 | ~Thread(); 21 | 22 | Thread& operator=(const Thread& other) = delete; 23 | Thread& operator=(Thread&& other) = delete; 24 | 25 | void setName(const std::string &name); 26 | static void setCurrentName(const std::string &name); 27 | 28 | bool start(std::function && fct); 29 | bool start(void *(*fct)(void *ctx), void *ctx); 30 | 31 | void join(); 32 | void detach(); 33 | void cancel(); 34 | 35 | inline pthread_t threadId() const { return thread_; } 36 | 37 | private: 38 | enum State 39 | { 40 | kNotRunning, 41 | kRunning, 42 | kDetached, 43 | kJoined, 44 | }; 45 | 46 | pthread_t thread_ = 0; 47 | State state_ = kNotRunning; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /mimosa/tpl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(FILES 2 | abstract-value.hh 3 | append-helper.hh 4 | cache.hh 5 | dict.hh 6 | include.hh 7 | list.hh 8 | log.hh 9 | map.hh 10 | parser.hh 11 | template.hh 12 | value.hh 13 | value.hxx 14 | 15 | DESTINATION include/mimosa/tpl/) 16 | 17 | install(FILES 18 | ast/empty.hh 19 | ast/repeated.hh 20 | ast/root.hh 21 | ast/text.hh 22 | ast/var.hh 23 | ast/node.hh 24 | 25 | DESTINATION include/mimosa/tpl/ast/) 26 | 27 | add_library(mimosa-tpl STATIC 28 | abstract-value.cc 29 | cache.cc 30 | dict.cc 31 | filter-factory.cc 32 | include.cc 33 | list.cc 34 | log.cc 35 | parser.cc 36 | template.cc 37 | 38 | ast/empty.cc 39 | ast/repeated.cc 40 | ast/root.cc 41 | ast/text.cc 42 | ast/var.cc 43 | ) 44 | target_link_libraries(mimosa-tpl PUBLIC mimosa) 45 | 46 | install(TARGETS mimosa-tpl 47 | RUNTIME DESTINATION bin 48 | LIBRARY DESTINATION lib 49 | ARCHIVE DESTINATION lib) 50 | 51 | add_subdirectory(tests) 52 | -------------------------------------------------------------------------------- /mimosa/tpl/abstract-value.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "abstract-value.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace tpl 8 | { 9 | AbstractValue::AbstractValue(std::string name) 10 | : parent_(nullptr), 11 | name_(std::move(name)) 12 | { 13 | } 14 | 15 | AbstractValue::SingleValueIterator::SingleValueIterator(const AbstractValue * value) 16 | : value_(value) 17 | { 18 | } 19 | 20 | const AbstractValue * 21 | AbstractValue::SingleValueIterator::value() const 22 | { 23 | return value_; 24 | } 25 | 26 | void 27 | AbstractValue::SingleValueIterator::next() 28 | { 29 | value_ = nullptr; 30 | } 31 | 32 | bool 33 | AbstractValue::SingleValueIterator::end() const 34 | { 35 | return !value_; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mimosa/tpl/abstract-value.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../ref-countable.hh" 4 | # include "../stream/stream.hh" 5 | # include "../string-ref.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace tpl 10 | { 11 | class AbstractValue : public RefCountable 12 | { 13 | public: 14 | explicit AbstractValue(std::string name = ""); 15 | 16 | virtual const AbstractValue * lookup(const StringRef & var) const = 0; 17 | virtual void write(stream::Stream::Ptr stream) const = 0; 18 | 19 | class Iterator : public RefCountable 20 | { 21 | public: 22 | virtual const AbstractValue * value() const = 0; 23 | virtual void next() = 0; 24 | virtual bool end() const = 0; 25 | }; 26 | 27 | class SingleValueIterator : public Iterator 28 | { 29 | public: 30 | MIMOSA_DEF_PTR(SingleValueIterator); 31 | 32 | explicit SingleValueIterator(const AbstractValue * value = nullptr); 33 | 34 | virtual const AbstractValue * value() const; 35 | virtual void next(); 36 | virtual bool end() const; 37 | 38 | private: 39 | const AbstractValue * value_; 40 | }; 41 | 42 | virtual Iterator::Ptr begin() const = 0; 43 | virtual bool empty() const = 0; 44 | 45 | inline const std::string & name() const { return name_; } 46 | 47 | const AbstractValue * parent_; 48 | std::string name_; 49 | }; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /mimosa/tpl/append-helper.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "value.hh" 4 | # include "include.hh" 5 | # include "template.hh" 6 | 7 | # define MIMOSA_TPL_APPEND_HELPER \ 8 | \ 9 | inline void append(const std::string & name, \ 10 | const char * value) \ 11 | { \ 12 | append(new Value(name, value)); \ 13 | } \ 14 | \ 15 | inline void append(const std::string & name, \ 16 | Template::ConstPtr tpl) \ 17 | { \ 18 | append(new Include(name, tpl)); \ 19 | } \ 20 | \ 21 | template \ 22 | inline void append(const std::string & name, \ 23 | const U & value) \ 24 | { \ 25 | append(new Value(name, value)); \ 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/empty.cc: -------------------------------------------------------------------------------- 1 | #include "empty.hh" 2 | #include "../abstract-value.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace tpl 7 | { 8 | namespace ast 9 | { 10 | Empty::~Empty() 11 | { 12 | while (!childs_.empty()) { 13 | auto child = childs_.front(); 14 | childs_.pop(); 15 | delete child; 16 | } 17 | } 18 | 19 | void 20 | Empty::execute(stream::Stream::Ptr stream, 21 | const AbstractValue & value) const 22 | { 23 | auto v = value.lookup(var_); 24 | if (v && !v->empty()) 25 | return; 26 | 27 | if (!v) 28 | v = &value; 29 | 30 | for (auto & child : childs_) 31 | child.execute(stream, *v); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/empty.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../../string-ref.hh" 4 | # include "node.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace tpl 9 | { 10 | namespace ast 11 | { 12 | class Empty : public Node 13 | { 14 | public: 15 | ~Empty(); 16 | 17 | virtual void execute(stream::Stream::Ptr stream, 18 | const AbstractValue & value) const; 19 | 20 | virtual void addChild(Node * node) { childs_.push(node); } 21 | virtual StringRef var() const { return var_; } 22 | 23 | StringRef var_; 24 | 25 | nodes_type childs_; 26 | }; 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/node.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../../ref-countable.hh" 4 | # include "../../stream/stream.hh" 5 | # include "../../string-ref.hh" 6 | # include "../../intrusive-slist.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace tpl 11 | { 12 | class AbstractValue; 13 | 14 | namespace ast 15 | { 16 | class Node 17 | { 18 | public: 19 | virtual ~Node() {} 20 | 21 | virtual void execute(stream::Stream::Ptr stream, 22 | const AbstractValue & value) const = 0; 23 | 24 | virtual void addChild(Node * /*node*/) {} 25 | virtual StringRef var() const { return "(none)"; } 26 | 27 | typedef IntrusiveSlistHook hook_type; 28 | 29 | hook_type hook_; 30 | uint16_t line_; 31 | uint16_t col_; 32 | 33 | typedef IntrusiveSlist nodes_type; 34 | }; 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/repeated.cc: -------------------------------------------------------------------------------- 1 | #include "repeated.hh" 2 | #include "../abstract-value.hh" 3 | 4 | namespace mimosa 5 | { 6 | namespace tpl 7 | { 8 | namespace ast 9 | { 10 | Repeated::~Repeated() 11 | { 12 | while (!childs_.empty()) { 13 | auto child = childs_.front(); 14 | childs_.pop(); 15 | delete child; 16 | } 17 | } 18 | 19 | void 20 | Repeated::execute(stream::Stream::Ptr stream, 21 | const AbstractValue & value) const 22 | { 23 | auto v = value.lookup(var_); 24 | if (!v || v->empty()) 25 | return; 26 | 27 | for (auto it = v->begin(); !it->end(); it->next()) 28 | { 29 | for (auto & child : childs_) 30 | if (it->value()) 31 | child.execute(stream, *it->value()); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/repeated.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../../string-ref.hh" 4 | # include "node.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace tpl 9 | { 10 | namespace ast 11 | { 12 | class Repeated : public Node 13 | { 14 | public: 15 | ~Repeated(); 16 | virtual void execute(stream::Stream::Ptr stream, 17 | const AbstractValue & value) const; 18 | 19 | virtual void addChild(Node * node) { childs_.push(node); } 20 | virtual StringRef var() const { return var_; } 21 | 22 | StringRef var_; 23 | 24 | nodes_type childs_; 25 | }; 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/root.cc: -------------------------------------------------------------------------------- 1 | #include "root.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace tpl 6 | { 7 | namespace ast 8 | { 9 | Root::Root(const Template & tpl) 10 | : tpl_(tpl) 11 | { 12 | } 13 | 14 | Root::~Root() 15 | { 16 | while (!childs_.empty()) { 17 | auto child = childs_.front(); 18 | childs_.pop(); 19 | delete child; 20 | } 21 | } 22 | 23 | void 24 | Root::execute(stream::Stream::Ptr stream, 25 | const AbstractValue & value) const 26 | { 27 | for (auto & child : childs_) 28 | child.execute(stream, value); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/root.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "node.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace tpl 8 | { 9 | class Template; 10 | 11 | namespace ast 12 | { 13 | class Root : public Node 14 | { 15 | public: 16 | Root(const Template & tpl); 17 | ~Root(); 18 | 19 | virtual void execute(stream::Stream::Ptr stream, 20 | const AbstractValue & value) const; 21 | virtual void addChild(Node * node) { childs_.push(node); } 22 | 23 | const Template & tpl_; 24 | nodes_type childs_; 25 | }; 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/text.cc: -------------------------------------------------------------------------------- 1 | #include "text.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace tpl 6 | { 7 | namespace ast 8 | { 9 | void 10 | Text::execute(stream::Stream::Ptr stream, 11 | const AbstractValue & /*value*/) const 12 | { 13 | stream->write(text_.data(), text_.size()); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/text.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "../../string-ref.hh" 4 | # include "node.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace tpl 9 | { 10 | namespace ast 11 | { 12 | class Text : public Node 13 | { 14 | public: 15 | virtual void execute(stream::Stream::Ptr stream, 16 | const AbstractValue & value) const; 17 | 18 | 19 | StringRef text_; 20 | }; 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/var.cc: -------------------------------------------------------------------------------- 1 | #include "../abstract-value.hh" 2 | #include "var.hh" 3 | #include "../filter-factory.hh" 4 | #include "../../format/format-stream.hh" 5 | #include "../../options/options.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace tpl 10 | { 11 | auto & TPL_DEBUG = *options::addSwitch("tpl", "tpl-debug", "helps debugging of template"); 12 | 13 | namespace ast 14 | { 15 | void 16 | Var::execute(stream::Stream::Ptr stream, 17 | const AbstractValue & value) const 18 | { 19 | const AbstractValue * v = &value; 20 | 21 | for (const auto & var : vars_) 22 | { 23 | v = v->lookup(var); 24 | if (!v) 25 | goto not_found; 26 | } 27 | 28 | for (const auto & filter : filters_) 29 | stream = FilterFactory::instance().create((std::string)filter, stream); 30 | 31 | if (v) 32 | v->write(stream); 33 | else 34 | not_found: 35 | if (TPL_DEBUG) 36 | format::format(*stream, "(%s not found)", var()); 37 | } 38 | 39 | StringRef 40 | Var::var() const 41 | { 42 | if (vars_.empty()) 43 | return "(empty)"; 44 | return vars_.front(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mimosa/tpl/ast/var.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../../string-ref.hh" 6 | # include "../../stream/stream.hh" 7 | # include "node.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace tpl 12 | { 13 | namespace ast 14 | { 15 | class Var : public Node 16 | { 17 | public: 18 | virtual void execute(stream::Stream::Ptr stream, 19 | const AbstractValue & value) const; 20 | 21 | virtual StringRef var() const; 22 | 23 | std::vector vars_; 24 | std::vector filters_; 25 | }; 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /mimosa/tpl/cache.cc: -------------------------------------------------------------------------------- 1 | #include "cache.hh" 2 | #include "../expiring-cache.hxx" // contains template definition 3 | 4 | namespace mimosa 5 | { 6 | namespace tpl 7 | { 8 | Cache::Cache() 9 | { 10 | setEntryTimeout(minute * 15); 11 | setValueTimeout(hour); 12 | setCleanupPeriod(minute); 13 | startCleanupThread(); 14 | } 15 | 16 | void 17 | Cache::cacheMiss(const std::string & key) 18 | { 19 | set(key, Template::parseFile(key)); 20 | } 21 | } 22 | } 23 | 24 | template class mimosa::ExpiringCache; 25 | -------------------------------------------------------------------------------- /mimosa/tpl/cache.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../expiring-cache.hh" 4 | #include "template.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace tpl 9 | { 10 | class Cache : public mimosa::ExpiringCache 11 | { 12 | public: 13 | Cache(); 14 | virtual ~Cache() = default; 15 | 16 | protected: 17 | virtual void cacheMiss(const std::string & key); 18 | }; 19 | } 20 | } 21 | 22 | extern template class mimosa::ExpiringCache; 23 | 24 | -------------------------------------------------------------------------------- /mimosa/tpl/dict.cc: -------------------------------------------------------------------------------- 1 | #include "dict.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace tpl 6 | { 7 | Dict::Dict(const std::string & name) 8 | : AbstractValue(name) 9 | { 10 | } 11 | 12 | const AbstractValue * 13 | Dict::lookup(const StringRef & var) const 14 | { 15 | if (var == ".") 16 | return this; 17 | 18 | auto it = values_.find((std::string)var); 19 | if (it != values_.end()) 20 | return it->second.get(); 21 | 22 | if (parent_) 23 | return parent_->lookup(var); 24 | return nullptr; 25 | } 26 | 27 | void 28 | Dict::write(stream::Stream::Ptr /*stream*/) const 29 | { 30 | } 31 | 32 | AbstractValue::Iterator::Ptr 33 | Dict::begin() const 34 | { 35 | return new DictIterator(this, values_.begin()); 36 | } 37 | 38 | bool 39 | Dict::empty() const 40 | { 41 | return values_.empty(); 42 | } 43 | 44 | Dict::DictIterator::DictIterator(const Dict * value, 45 | const values_type::const_iterator & it) 46 | : value_(value), 47 | it_(it) 48 | { 49 | } 50 | 51 | const AbstractValue * 52 | Dict::DictIterator::value() const 53 | { 54 | return it_->second.get(); 55 | } 56 | 57 | void 58 | Dict::DictIterator::next() 59 | { 60 | ++it_; 61 | } 62 | 63 | bool 64 | Dict::DictIterator::end() const 65 | { 66 | return it_ == value_->values_.end(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /mimosa/tpl/dict.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "abstract-value.hh" 6 | # include "append-helper.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace tpl 11 | { 12 | class Dict : public AbstractValue 13 | { 14 | public: 15 | MIMOSA_DEF_PTR(Dict); 16 | 17 | explicit Dict(const std::string & name = ""); 18 | 19 | virtual const AbstractValue * lookup(const StringRef & var) const; 20 | virtual void write(stream::Stream::Ptr stream) const; 21 | 22 | virtual Iterator::Ptr begin() const; 23 | virtual bool empty() const; 24 | 25 | typedef std::unordered_map values_type; 26 | 27 | inline void append(AbstractValue::Ptr value) 28 | { 29 | value->parent_ = this; 30 | values_[value->name()] = value; 31 | } 32 | 33 | MIMOSA_TPL_APPEND_HELPER 34 | 35 | class DictIterator : public Iterator 36 | { 37 | public: 38 | MIMOSA_DEF_PTR(DictIterator); 39 | 40 | DictIterator(const Dict * value, 41 | const values_type::const_iterator & it); 42 | 43 | virtual const AbstractValue * value() const; 44 | virtual void next(); 45 | virtual bool end() const; 46 | 47 | private: 48 | const Dict * value_; 49 | values_type::const_iterator it_; 50 | }; 51 | 52 | private: 53 | values_type values_; 54 | }; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /mimosa/tpl/filter-factory.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "../shared-mutex.hh" 7 | # include "../stream/filter.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace tpl 12 | { 13 | class FilterFactory 14 | { 15 | public: 16 | typedef stream::Filter::Ptr (*creator_type)(stream::Stream::Ptr); 17 | 18 | FilterFactory(); 19 | ~FilterFactory(); 20 | 21 | static FilterFactory & instance(); 22 | 23 | stream::Stream::Ptr create(const std::string & filter, 24 | stream::Stream::Ptr stream) const; 25 | 26 | bool registerFilter(const std::string & filter, 27 | creator_type creator); 28 | 29 | private: 30 | mutable SharedMutex rwlock_; 31 | std::unordered_map creators_; 32 | }; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /mimosa/tpl/include.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "include.hh" 6 | 7 | namespace mimosa 8 | { 9 | namespace tpl 10 | { 11 | Include::Include(const std::string & name, 12 | Template::ConstPtr tpl) 13 | : AbstractValue(name), 14 | tpl_(std::move(std::move(tpl))) 15 | { 16 | } 17 | 18 | const AbstractValue * 19 | Include::lookup(const StringRef & var) const 20 | { 21 | if (var == "." || var == name_) 22 | return this; 23 | if (parent_) 24 | return parent_->lookup(var); 25 | return nullptr; 26 | } 27 | 28 | void 29 | Include::write(stream::Stream::Ptr stream) const 30 | { 31 | tpl_->execute(stream, *this); 32 | } 33 | 34 | AbstractValue::Iterator::Ptr 35 | Include::begin() const 36 | { 37 | return new AbstractValue::SingleValueIterator(this); 38 | } 39 | 40 | bool 41 | Include::empty() const 42 | { 43 | return false; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /mimosa/tpl/include.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include "template.hh" 4 | # include "abstract-value.hh" 5 | 6 | namespace mimosa 7 | { 8 | namespace tpl 9 | { 10 | class Include : public AbstractValue 11 | { 12 | public: 13 | MIMOSA_DEF_PTR(Include); 14 | 15 | explicit Include(const std::string & name, Template::ConstPtr tpl); 16 | 17 | virtual const AbstractValue * lookup(const StringRef & var) const; 18 | virtual void write(stream::Stream::Ptr stream) const; 19 | 20 | virtual Iterator::Ptr begin() const; 21 | virtual bool empty() const; 22 | 23 | Template::ConstPtr tpl_; 24 | }; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mimosa/tpl/list.cc: -------------------------------------------------------------------------------- 1 | #include "list.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace tpl 6 | { 7 | List::List(const std::string & name) 8 | : AbstractValue(name) 9 | { 10 | } 11 | 12 | const AbstractValue * 13 | List::lookup(const StringRef & var) const 14 | { 15 | if (var == "." || var == name_) 16 | return this; 17 | if (parent_) 18 | return parent_->lookup(var); 19 | return nullptr; 20 | } 21 | 22 | void 23 | List::write(stream::Stream::Ptr /*stream*/) const 24 | { 25 | } 26 | 27 | AbstractValue::Iterator::Ptr 28 | List::begin() const 29 | { 30 | return new ListIterator(this, values_.begin()); 31 | } 32 | 33 | bool 34 | List::empty() const 35 | { 36 | return values_.empty(); 37 | } 38 | 39 | List::ListIterator::ListIterator(const List * value, 40 | const values_type::const_iterator & it) 41 | : value_(value), 42 | it_(it) 43 | { 44 | } 45 | 46 | const AbstractValue * 47 | List::ListIterator::value() const 48 | { 49 | return it_->get(); 50 | } 51 | 52 | void 53 | List::ListIterator::next() 54 | { 55 | ++it_; 56 | } 57 | 58 | bool 59 | List::ListIterator::end() const 60 | { 61 | return it_ == value_->values_.end(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /mimosa/tpl/list.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "abstract-value.hh" 6 | # include "append-helper.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace tpl 11 | { 12 | class List : public AbstractValue 13 | { 14 | public: 15 | MIMOSA_DEF_PTR(List); 16 | 17 | explicit List(const std::string & name = ""); 18 | 19 | virtual const AbstractValue * lookup(const StringRef & var) const; 20 | virtual void write(stream::Stream::Ptr stream) const; 21 | 22 | virtual Iterator::Ptr begin() const; 23 | virtual bool empty() const; 24 | 25 | typedef std::vector values_type; 26 | 27 | inline void append(AbstractValue::Ptr value) 28 | { 29 | value->parent_ = this; 30 | values_.push_back(value.get()); 31 | } 32 | 33 | MIMOSA_TPL_APPEND_HELPER 34 | 35 | class ListIterator : public Iterator 36 | { 37 | public: 38 | MIMOSA_DEF_PTR(ListIterator); 39 | 40 | ListIterator(const List * value, 41 | const values_type::const_iterator & it); 42 | 43 | virtual const AbstractValue * value() const; 44 | virtual void next(); 45 | virtual bool end() const; 46 | 47 | private: 48 | const List * value_; 49 | values_type::const_iterator it_; 50 | }; 51 | 52 | private: 53 | values_type values_; 54 | }; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /mimosa/tpl/log.cc: -------------------------------------------------------------------------------- 1 | #include "log.hh" 2 | 3 | namespace mimosa 4 | { 5 | namespace tpl 6 | { 7 | log::Origin * tpl_log = new log::Origin("template", log::kWarning); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mimosa/tpl/log.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../log/log.hh" 4 | 5 | namespace mimosa 6 | { 7 | namespace tpl 8 | { 9 | extern mimosa::log::Origin * tpl_log; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /mimosa/tpl/map.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | namespace mimosa 6 | { 7 | namespace tpl 8 | { 9 | template 10 | class Value : public AbstractValue 11 | { 12 | public: 13 | virtual void write(const StringRef & var, 14 | stream::Stream::Ptr stream); 15 | 16 | std::unordered_map values_; 17 | }; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /mimosa/tpl/parser.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | # include 5 | 6 | # include "template.hh" 7 | # include "../string-ref.hh" 8 | 9 | namespace mimosa 10 | { 11 | namespace tpl 12 | { 13 | class Parser 14 | { 15 | public: 16 | explicit Parser(const Template & tpl); 17 | ~Parser(); 18 | 19 | void reset(); 20 | 21 | ast::Root * parse(); 22 | 23 | bool parseText(); 24 | bool parseAction(); 25 | bool parseRepeat(); 26 | bool parseRepeatEmpty(); 27 | bool parseEmpty(); 28 | bool parseEnd(); 29 | bool parseExpand(); 30 | 31 | private: 32 | std::string action_start_; 33 | std::string action_end_; 34 | 35 | StringRef input_; 36 | 37 | std::vector stack_; 38 | int line_; 39 | int column_; 40 | 41 | ast::Root * root_; 42 | }; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /mimosa/tpl/template.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../string-ref.hh" 5 | #include "../stream/fd-stream.hh" 6 | #include "template.hh" 7 | #include "parser.hh" 8 | #include "ast/text.hh" 9 | 10 | namespace mimosa 11 | { 12 | namespace tpl 13 | { 14 | Template::~Template() 15 | { 16 | delete root_; 17 | } 18 | 19 | Template::Ptr 20 | Template::parseString(const std::string & str) 21 | { 22 | Template::Ptr tpl(new Template); 23 | 24 | tpl->data_ = str; 25 | 26 | Parser parser(*tpl); 27 | tpl->root_ = parser.parse(); 28 | if (tpl->root_) 29 | return tpl; 30 | return nullptr; 31 | } 32 | 33 | Template::Ptr 34 | Template::parseFile(const std::string & path) 35 | { 36 | auto stream = stream::FdStream::openFile(path.c_str()); 37 | if (!stream) 38 | return nullptr; 39 | 40 | std::string data; 41 | while (true) 42 | { 43 | auto buffer = stream->read(); 44 | if (!buffer) 45 | break; 46 | data.append(buffer->data(), buffer->size()); 47 | } 48 | stream = nullptr; 49 | 50 | auto tpl = parseString(data); 51 | if (tpl) 52 | tpl->filename_ = path; 53 | return tpl; 54 | } 55 | 56 | void 57 | Template::execute(stream::Stream::Ptr stream, 58 | const AbstractValue & value) const 59 | { 60 | root_->execute(std::move(stream), value); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mimosa/tpl/template.doch: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | @page template 4 | 5 | @section template_syntax The template syntax 6 | 7 | @verbatim 8 | {{var}} will expend var, a variable must match [^|]+ and not contain }} 9 | {{var|filter}} will apply filter on the output of var, usefull for html, javascript, ... 10 | {{var.attr}} is equivalent to {{*var}}{{attr}}{{/attr}}, this is particulary usefull if 11 | var is a dict. 12 | 13 | {{*list}} T {{/}} 14 | {{*list}} T {{/list}} will expand the enclosed data for each values. 15 | {{.}} represents the current value of the iterated list 16 | 17 | {{*list}} T1 {{*!}} T2 {{/}} 18 | {{*list}} T1 {{*!list}} T2 {{/list}} will expend the enclosed data if list is not defined or empty 19 | 20 | {{!list}} T {{/}} 21 | {{!list}} T {{/list}} will expend the enclosed data if list is not defined or empty 22 | @endverbatim 23 | 24 | */ 25 | -------------------------------------------------------------------------------- /mimosa/tpl/template.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | # include 4 | 5 | # include "../ref-countable.hh" 6 | # include "ast/root.hh" 7 | 8 | namespace mimosa 9 | { 10 | namespace tpl 11 | { 12 | class Parser; 13 | class Template : public RefCountable