├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── demos ├── 02_stop │ ├── CMakeLists.txt │ ├── readme.md │ └── server.cc ├── 03_parallel │ ├── CMakeLists.txt │ ├── parallel01.cc │ └── readme.md ├── 04_wget │ ├── CMakeLists.txt │ └── wget.cc ├── 05_http_echo │ ├── CMakeLists.txt │ └── echo.cc ├── 06_http_proxy │ ├── CMakeLists.txt │ └── proxy.cc ├── 07_http │ ├── 07_http_no_reply.cc │ ├── 07_http_req.cc │ ├── 07_http_simple.cc │ ├── CMakeLists.txt │ ├── http_echo_defer.cc │ ├── http_parallel.cc │ └── http_series.cc ├── 08_max_con │ ├── CMakeLists.txt │ ├── client01.cc │ ├── client02.cc │ └── server.cc ├── 09_timer │ ├── CMakeLists.txt │ ├── timer01.cc │ └── timer02.cc ├── 10_http_forward │ ├── CMakeLists.txt │ └── forward.cc ├── 11_life_cycle │ ├── CMakeLists.txt │ └── life.cc ├── 12_counter │ ├── CMakeLists.txt │ ├── counter_intro.cc │ └── counter_to_parallel.cc ├── 13_block_series │ └── block_series.cc ├── 14_restful │ ├── 2.txt │ ├── CMakeLists.txt │ ├── base64.cc │ ├── base64.h │ ├── encode.h │ ├── readme.md │ ├── restful.py │ ├── restful_client.cc │ ├── restful_server.cc │ └── wine.jpg ├── 15_file │ ├── 15_file_server_01.cc │ ├── 15_file_server_02.cc │ ├── 15_file_write.cc │ └── CMakeLists.txt ├── 16_graph │ ├── 16_graph_00.cc │ ├── 16_graph_01.cc │ ├── 16_graph_02.cc │ └── CMakeLists.txt ├── 17_go_task │ ├── CMakeLists.txt │ ├── go.cc │ └── go_simple.cc ├── 18_con_ctx │ └── ctx.cc ├── 19_parallel │ ├── CMakeLists.txt │ └── get_all_para.cc ├── 20_dynamic │ ├── CMakeLists.txt │ └── dynamic.cc ├── 21_cmp │ ├── 21_clent01.cc │ ├── 21_client02.cc │ ├── 21_server.cc │ ├── CMakeLists.txt │ └── test02.cc ├── 22_dns │ ├── 22_dns_01.cc │ ├── 22_dns_02.cc │ ├── 22_dns_03.cc │ ├── 22_dns_04.cc │ ├── 22_dns_05.cc │ ├── 22_dns_server.cc │ ├── 22_resolver_01.cc │ ├── 22_test_dns_cache.cc │ └── CMakeLists.txt ├── 23_list │ ├── 23_list_01.cc │ ├── 23_list_01_init.c │ ├── 23_list_02_add.c │ ├── 23_list_03_del.c │ ├── 23_list_04_move.c │ ├── 23_list_05_splice.c │ ├── 23_list_05_splice_init.c │ ├── 24_06_list_traverse.c │ ├── CMakeLists.txt │ └── list.h ├── 24_thrd_task │ ├── 24_thrd_task_01.cc │ ├── 24_thrd_task_02.cc │ └── CMakeLists.txt ├── 25_msgque │ ├── 25_msgque.cc │ ├── CMakeLists.txt │ ├── msgqueue.c │ └── msgqueue.h ├── 26_resource_pool │ ├── 26_issue_559_client.cc │ ├── 26_issue_559_server.cc │ ├── 26_resource_pool_01.cc │ ├── 26_resource_pool_02.cc │ ├── 26_resource_pool_03.cc │ └── CMakeLists.txt ├── 27_parse_uri │ ├── 27_request_uri_split.cc │ ├── 27_unorderd_split.cc │ ├── 27_uri_parser_01.cc │ └── CMakeLists.txt ├── 28_string_util │ ├── 28_string_01.cc │ └── CMakeLists.txt ├── 29_upstream │ ├── 29_upstream_hash.cc │ ├── 29_upstream_hash_define.cc │ ├── 29_upstream_manual.cc │ ├── 29_upstream_random.cc │ ├── 29_upstream_server.cc │ ├── 29_upstream_weighted.cc │ ├── CMakeLists.txt │ └── readme.md ├── 30_kernel_comm │ ├── 30_kernel_comm_01.cc │ ├── 30_test_server.cc │ └── CMakeLists.txt ├── 31_mysql │ ├── 31_01_show_db.cc │ ├── 31_02_conn.cc │ ├── 31_mysql_cli.cc │ ├── 31_mysql_intro_demo.cc │ └── CMakeLists.txt ├── 32_cpu_server │ └── readme.md ├── 33_header │ ├── 33_header_pair.cc │ ├── CMakeLists.txt │ └── test.py ├── 34_https │ ├── 34_https_test.cc │ ├── CMakeLists.txt │ ├── cacert.pem │ ├── gen.sh │ ├── server.crt │ └── server.key ├── 35_dismiss │ ├── 35_dismiss_test.cc │ └── CMakeLists.txt ├── 36_task │ ├── 36_parallel.cc │ ├── 36_series.cc │ └── CMakeLists.txt ├── 37_rb_tree │ ├── 37_rb_tree_01.c │ ├── Makefile │ ├── rbtree.c │ └── rbtree.h ├── 38_json_parser │ ├── json_parser.c │ ├── json_parser.h │ ├── list.h │ ├── rbtree.c │ ├── rbtree.h │ ├── test.c │ ├── test.json │ └── test_speed.c ├── 3rd │ ├── json.hpp │ └── util.h ├── CMakeLists.txt ├── deprecated │ ├── logger.c │ └── logger.h ├── other │ ├── 01_other.cc │ └── CMakeLists.txt └── readme.md ├── other ├── 01_transfer_encoding.md ├── Json │ ├── json.hpp │ └── test01.cc ├── base_to_derived │ └── test.cc ├── c_thread │ ├── 01_pthread_key_t.c │ ├── 02_pthread_key_t.c │ └── readme.md ├── callback │ ├── func_ptr.cc │ ├── test.cc │ └── test2.cc ├── callback_param │ ├── test.cc │ └── test_01.cc ├── cmake │ ├── find_cmake.md │ ├── find_package.md │ └── install.md ├── cookie │ └── readme.md ├── cors │ └── readme.md ├── dns │ ├── 02_dns.md │ ├── 03_dns_linux.md │ ├── 04_http_dns.md │ └── 06_addr_info.md ├── global │ ├── a.h │ ├── global.cc │ ├── global.h │ └── main.cc ├── http_router │ ├── 01_libhv.md │ └── readme.md ├── inherit │ ├── 01.cc │ ├── 02.cc │ ├── 03.cc │ └── 04.cc ├── inl_file │ ├── A.h │ ├── A.inl │ └── main.cc ├── lambda │ └── 01.cc ├── map_case_intensive │ ├── test01.cc │ └── test02.cc ├── map_vs_umap │ └── bench.cc ├── mysql │ └── readme.md ├── name_service │ └── 05_name_service.md ├── post │ ├── multi_part_form.md │ ├── multipart-parser-c.md │ └── readme.md ├── relpath │ ├── test.cc │ └── text.txt ├── size │ ├── 01.cc │ ├── 02.cc │ └── 03.cc ├── test │ └── test.cc ├── time │ └── test.cc ├── todo.md ├── unordered_map │ ├── 01.cc │ └── 02.cc ├── web_template │ └── readme.md └── wfrest_exp │ └── pics │ ├── cookie01.png │ ├── cookie02.png │ └── cookie03.png ├── src_analysis ├── 02_epoll.md ├── 02_epoll_01.md ├── 02_epoll_02.md ├── 03_communicate.md ├── 05_poller_opt.md ├── 06_dns.md ├── 06_dns_01.md ├── 06_dns_02.md ├── 06_dns_03.md ├── 06_dns_cache.md ├── 06_dns_protocol.md ├── 06_dns_routine.md ├── 08_msgqueue.md ├── 11_parallel.md ├── 11_subtask.md ├── 12_go_task.md ├── 12_thread_task.md ├── 13_concept.md ├── 14_thrd_pool.md ├── 15_timer_task.md ├── 18_http_01.md ├── 18_http_02.md ├── 18_http_03.md ├── 18_http_04.md ├── 19_resource_pool.md ├── 19_resource_pool_01.md ├── 20_RouteManager.md ├── 21_rb_tree_opt.md ├── 22_http_server_00.md ├── 22_http_server_01.md ├── 22_http_server_02.md ├── 23_json_01_parse.md ├── 23_json_02_access.md ├── 24_list.md ├── 25_rb_tree.md ├── 26_http_parser.md ├── mysql_intro.md ├── other_00_http_improve.md ├── other_01_cache_lock.md ├── other_02_dns_opt.md ├── other_03_cache_size.md ├── other_04_task_defer_delete.md ├── other_05_faq_62.md └── pics │ ├── CommSchedObject.png │ ├── UMLClassDiagram-WFTaskFactory-inl.png │ ├── appen_list.jpeg │ ├── dns_cache_01.png │ ├── dns_cache_02.png │ ├── dns_cache_03.png │ ├── dns_cache_04.png │ ├── dns_protocol.png │ ├── exeReuest.png │ ├── http01.png │ ├── json_arr.png │ ├── json_num.png │ ├── json_obj.png │ ├── json_str.png │ ├── json_val.png │ ├── message_out.png │ ├── message_out01.png │ ├── mysql_io.png │ ├── networktask.png │ ├── subtask.png │ ├── subtasks.png │ └── task_arch.png └── workflow ├── .cpptree.list ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CMakeLists_Headers.txt ├── CODE_OF_CONDUCT.md ├── README.md ├── README_cn.md ├── benchmark ├── CMakeLists.txt ├── README.md ├── benchmark-01-http_server.cc ├── benchmark-02-http_server_long_req.cc └── util │ ├── args.h │ ├── content.h │ └── date.h ├── build.cmake └── config.toinstall.cmake ├── calltree.pl ├── cpptree.pl ├── docs ├── about-config.md ├── about-connection-context.md ├── about-counter.md ├── about-dns.md ├── about-error.md ├── about-exit.md ├── about-go-task.md ├── about-service-management.md ├── about-timeout.md ├── about-timer.md ├── about-upstream.md ├── benchmark.md ├── en │ ├── CONTRIBUTING.md │ ├── about-config.md │ ├── about-connection-context.md │ ├── about-counter.md │ ├── about-dns.md │ ├── about-error.md │ ├── about-exit.md │ ├── about-go-task.md │ ├── about-service-management.md │ ├── about-timeout.md │ ├── about-timer.md │ ├── about-upstream.md │ ├── tutorial-01-wget.md │ ├── tutorial-02-redis_cli.md │ ├── tutorial-03-wget_to_redis.md │ ├── tutorial-04-http_echo_server.md │ ├── tutorial-05-http_proxy.md │ ├── tutorial-06-parallel_wget.md │ ├── tutorial-07-sort_task.md │ ├── tutorial-08-matrix_multiply.md │ ├── tutorial-09-http_file_server.md │ ├── tutorial-10-user_defined_protocol.md │ ├── tutorial-12-mysql_cli.md │ └── tutorial-13-kafka_cli.md ├── tutorial-01-wget.md ├── tutorial-02-redis_cli.md ├── tutorial-03-wget_to_redis.md ├── tutorial-04-http_echo_server.md ├── tutorial-05-http_proxy.md ├── tutorial-06-parallel_wget.md ├── tutorial-07-sort_task.md ├── tutorial-08-matrix_multiply.md ├── tutorial-09-http_file_server.md ├── tutorial-10-user_defined_protocol.md ├── tutorial-12-mysql_cli.md └── tutorial-13-kafka_cli.md ├── src ├── CMakeLists.txt ├── algorithm │ ├── CMakeLists.txt │ ├── DnsRoutine.cc │ ├── DnsRoutine.h │ ├── MapReduce.h │ └── MapReduce.inl ├── client │ ├── CMakeLists.txt │ ├── WFDnsClient.cc │ ├── WFDnsClient.h │ ├── WFKafkaClient.cc │ ├── WFKafkaClient.h │ ├── WFMySQLConnection.cc │ └── WFMySQLConnection.h ├── factory │ ├── CMakeLists.txt │ ├── DnsTaskImpl.cc │ ├── FileTaskImpl.cc │ ├── HttpTaskImpl.cc │ ├── KafkaTaskImpl.cc │ ├── KafkaTaskImpl.inl │ ├── MySQLTaskImpl.cc │ ├── RedisTaskImpl.cc │ ├── WFAlgoTaskFactory.h │ ├── WFAlgoTaskFactory.inl │ ├── WFConnection.h │ ├── WFGraphTask.cc │ ├── WFGraphTask.h │ ├── WFOperator.h │ ├── WFResourcePool.cc │ ├── WFResourcePool.h │ ├── WFTask.h │ ├── WFTask.inl │ ├── WFTaskError.h │ ├── WFTaskFactory.cc │ ├── WFTaskFactory.h │ ├── WFTaskFactory.inl │ ├── Workflow.cc │ └── Workflow.h ├── include │ └── workflow │ │ ├── CommRequest.h │ │ ├── CommScheduler.h │ │ ├── Communicator.h │ │ ├── DnsCache.h │ │ ├── DnsMessage.h │ │ ├── DnsRoutine.h │ │ ├── DnsUtil.h │ │ ├── EncodeStream.h │ │ ├── EndpointParams.h │ │ ├── ExecRequest.h │ │ ├── Executor.h │ │ ├── HttpMessage.h │ │ ├── HttpUtil.h │ │ ├── IORequest.h │ │ ├── IOService_linux.h │ │ ├── IOService_thread.h │ │ ├── KafkaDataTypes.h │ │ ├── KafkaMessage.h │ │ ├── KafkaResult.h │ │ ├── KafkaTaskImpl.inl │ │ ├── LRUCache.h │ │ ├── MD5Util.h │ │ ├── MapReduce.h │ │ ├── MapReduce.inl │ │ ├── MySQLMessage.h │ │ ├── MySQLMessage.inl │ │ ├── MySQLResult.h │ │ ├── MySQLResult.inl │ │ ├── ProtocolMessage.h │ │ ├── RedisMessage.h │ │ ├── RouteManager.h │ │ ├── SSLWrapper.h │ │ ├── SleepRequest.h │ │ ├── StringUtil.h │ │ ├── SubTask.h │ │ ├── URIParser.h │ │ ├── UpstreamManager.h │ │ ├── UpstreamPolicies.h │ │ ├── WFAlgoTaskFactory.h │ │ ├── WFAlgoTaskFactory.inl │ │ ├── WFConnection.h │ │ ├── WFDnsClient.h │ │ ├── WFDnsResolver.h │ │ ├── WFDnsServer.h │ │ ├── WFFacilities.h │ │ ├── WFFacilities.inl │ │ ├── WFFuture.h │ │ ├── WFGlobal.h │ │ ├── WFGraphTask.h │ │ ├── WFHttpServer.h │ │ ├── WFKafkaClient.h │ │ ├── WFMySQLConnection.h │ │ ├── WFMySQLServer.h │ │ ├── WFNameService.h │ │ ├── WFOperator.h │ │ ├── WFRedisServer.h │ │ ├── WFResourcePool.h │ │ ├── WFServer.h │ │ ├── WFServiceGovernance.h │ │ ├── WFTask.h │ │ ├── WFTask.inl │ │ ├── WFTaskError.h │ │ ├── WFTaskFactory.h │ │ ├── WFTaskFactory.inl │ │ ├── Workflow.h │ │ ├── crc32c.h │ │ ├── dns_parser.h │ │ ├── http_parser.h │ │ ├── kafka_parser.h │ │ ├── list.h │ │ ├── mpoller.h │ │ ├── msgqueue.h │ │ ├── mysql_byteorder.h │ │ ├── mysql_parser.h │ │ ├── mysql_stream.h │ │ ├── mysql_types.h │ │ ├── poller.h │ │ ├── rbtree.h │ │ ├── redis_parser.h │ │ └── thrdpool.h ├── kernel │ ├── CMakeLists.txt │ ├── CommRequest.cc │ ├── CommRequest.h │ ├── CommScheduler.cc │ ├── CommScheduler.h │ ├── Communicator.cc │ ├── Communicator.h │ ├── ExecRequest.h │ ├── Executor.cc │ ├── Executor.h │ ├── IORequest.h │ ├── IOService_linux.cc │ ├── IOService_linux.h │ ├── IOService_thread.cc │ ├── IOService_thread.h │ ├── SleepRequest.h │ ├── SubTask.cc │ ├── SubTask.h │ ├── list.h │ ├── logger.c │ ├── logger.h │ ├── mpoller.c │ ├── mpoller.h │ ├── msgqueue.c │ ├── msgqueue.h │ ├── poller.c │ ├── poller.h │ ├── rbtree.c │ ├── rbtree.h │ ├── thrdpool.c │ └── thrdpool.h ├── manager │ ├── CMakeLists.txt │ ├── DnsCache.cc │ ├── DnsCache.h │ ├── EndpointParams.h │ ├── RouteManager.cc │ ├── RouteManager.h │ ├── UpstreamManager.cc │ ├── UpstreamManager.h │ ├── WFFacilities.h │ ├── WFFacilities.inl │ ├── WFFuture.h │ ├── WFGlobal.cc │ └── WFGlobal.h ├── nameservice │ ├── CMakeLists.txt │ ├── UpstreamPolicies.cc │ ├── UpstreamPolicies.h │ ├── WFDnsResolver.cc │ ├── WFDnsResolver.h │ ├── WFNameService.cc │ ├── WFNameService.h │ ├── WFServiceGovernance.cc │ └── WFServiceGovernance.h ├── protocol │ ├── CMakeLists.txt │ ├── DnsMessage.cc │ ├── DnsMessage.h │ ├── DnsUtil.cc │ ├── DnsUtil.h │ ├── HttpMessage.cc │ ├── HttpMessage.h │ ├── HttpUtil.cc │ ├── HttpUtil.h │ ├── KafkaDataTypes.cc │ ├── KafkaDataTypes.h │ ├── KafkaMessage.cc │ ├── KafkaMessage.h │ ├── KafkaResult.cc │ ├── KafkaResult.h │ ├── MySQLMessage.cc │ ├── MySQLMessage.h │ ├── MySQLMessage.inl │ ├── MySQLResult.cc │ ├── MySQLResult.h │ ├── MySQLResult.inl │ ├── ProtocolMessage.h │ ├── RedisMessage.cc │ ├── RedisMessage.h │ ├── SSLWrapper.cc │ ├── SSLWrapper.h │ ├── dns_parser.c │ ├── dns_parser.h │ ├── http_parser.c │ ├── http_parser.h │ ├── kafka_parser.c │ ├── kafka_parser.h │ ├── mysql_byteorder.c │ ├── mysql_byteorder.h │ ├── mysql_parser.c │ ├── mysql_parser.h │ ├── mysql_stream.c │ ├── mysql_stream.h │ ├── mysql_types.h │ ├── redis_parser.c │ └── redis_parser.h ├── server │ ├── CMakeLists.txt │ ├── WFDnsServer.h │ ├── WFHttpServer.h │ ├── WFMySQLServer.cc │ ├── WFMySQLServer.h │ ├── WFRedisServer.h │ ├── WFServer.cc │ └── WFServer.h └── util │ ├── CMakeLists.txt │ ├── EncodeStream.cc │ ├── EncodeStream.h │ ├── LRUCache.h │ ├── MD5Util.cc │ ├── MD5Util.h │ ├── StringUtil.cc │ ├── StringUtil.h │ ├── URIParser.cc │ ├── URIParser.h │ ├── crc32c.c │ └── crc32c.h ├── test ├── CMakeLists.txt ├── algo_unittest.cc ├── dns_unittest.cc ├── facilities_unittest.cc ├── graph_unittest.cc ├── http_unittest.cc ├── memory_unittest.cc ├── mysql_unittest.cc ├── redis_unittest.cc ├── resource_unittest.cc ├── task_unittest.cc └── upstream_unittest.cc ├── tutorial ├── CMakeLists.txt ├── tutorial-00-helloworld.cc ├── tutorial-01-wget.cc ├── tutorial-02-redis_cli.cc ├── tutorial-03-wget_to_redis.cc ├── tutorial-04-http_echo_server.cc ├── tutorial-05-http_proxy.cc ├── tutorial-06-parallel_wget.cc ├── tutorial-07-sort_task.cc ├── tutorial-08-matrix_multiply.cc ├── tutorial-09-http_file_server.cc ├── tutorial-10-user_defined_protocol │ ├── client.cc │ ├── message.cc │ ├── message.h │ └── server.cc ├── tutorial-11-graph_task.cc ├── tutorial-12-mysql_cli.cc └── tutorial-13-kafka_cli.cc ├── workflow-config.cmake └── workflow-config.cmake.in /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all 2 | * 3 | 4 | # Unignore all with extensions 5 | !*.* 6 | 7 | # Unignore all dirs 8 | !*/ 9 | 10 | 11 | .DS_Store 12 | */.DS_Store 13 | 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | 43 | 44 | **/cmake-build-debug 45 | **/CMakeCache.txt 46 | **/cmake_install.cmake 47 | **/install_manifest.txt 48 | **/CMakeFiles/ 49 | **/CTestTestfile.cmake 50 | **/Makefile 51 | **/*.cbp 52 | **/CMakeScripts 53 | **/compile_commands.json 54 | 55 | include/divisible/* 56 | bin/* 57 | lib/* 58 | test/test_runner 59 | 60 | ## Local 61 | 62 | .idea/workspace.xml 63 | 64 | */build/* 65 | build/* 66 | build/release/* 67 | build/release-cpp11/* 68 | build/debug-cpp11/* 69 | build/debug/* 70 | build/run/* 71 | build/logs/& 72 | 73 | 74 | include/* 75 | lib/* 76 | bin/* 77 | .bash/ 78 | bin/bootstrap 79 | bin/lib-bash 80 | 81 | .idea 82 | 83 | .vscode 84 | 85 | # Ignore log 86 | *.log 87 | */logs/* 88 | */*log* 89 | 90 | */_include/* 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shiyu Yi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demos/02_stop/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(stop_server server.cc) 2 | target_link_libraries(stop_server workflow) 3 | -------------------------------------------------------------------------------- /demos/02_stop/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/demos/02_stop/readme.md -------------------------------------------------------------------------------- /demos/02_stop/server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // 命令行中用 curl -i "http://127.0.0.1/test" 6 | // https://github.com/sogou/workflow/issues/89 7 | // more elegant way : 8 | 9 | int main() 10 | { 11 | WFHttpServer server([&server](WFHttpTask *task) { // 这里的写法相当于一个defer作用 12 | if (strcmp(task->get_req()->get_request_uri(), "/stop") == 0) 13 | { 14 | static std::atomic flag; 15 | 16 | if (flag++ == 0) // shutdown只能调用一次,因此我们用了原子变量保护 17 | server.shutdown(); 18 | 19 | task->get_resp()->append_output_body("server stop"); 20 | return; 21 | } 22 | else if (strcmp(task->get_req()->get_request_uri(), "/test") == 0) 23 | { 24 | task->get_resp()->append_output_body("server test"); 25 | return; 26 | } 27 | 28 | /* Server’s logic */ 29 | // .... 30 | }); 31 | 32 | if (server.start(8888) == 0) 33 | server.wait_finish(); 34 | 35 | return 0; 36 | } 37 | 38 | /* 39 | // WFServer.h 40 | class WFServerBase : protected CommService 41 | { 42 | ... 43 | public: 44 | void stop() 45 | { 46 | this->shutdown(); 47 | this->wait_finish(); 48 | } 49 | 50 | void shutdown(); 51 | void wait_finish(); 52 | }; 53 | 54 | Server的stop方法无非就是shutdown+wait_finish,上述的方法就是将关停和等待结束分别在两个线程里调用 55 | 56 | 显然在process里直接调用stop则是一种错误。 57 | */ -------------------------------------------------------------------------------- /demos/03_parallel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(parallel01 parallel01.cc) 2 | target_link_libraries(parallel01 workflow) 3 | -------------------------------------------------------------------------------- /demos/03_parallel/readme.md: -------------------------------------------------------------------------------- 1 | ## ref 2 | 3 | https://github.com/sogou/workflow/blob/master/docs/tutorial-06-parallel_wget.md 4 | 5 | https://github.com/sogou/workflow/issues/135 -------------------------------------------------------------------------------- /demos/04_wget/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(wget wget.cc) 2 | target_link_libraries(wget workflow spdlog::spdlog) 3 | -------------------------------------------------------------------------------- /demos/05_http_echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(echo echo.cc) 2 | target_link_libraries(echo workflow spdlog::spdlog) 3 | -------------------------------------------------------------------------------- /demos/06_http_proxy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(06_proxy proxy.cc) 2 | target_link_libraries(06_proxy workflow) 3 | -------------------------------------------------------------------------------- /demos/07_http/07_http_no_reply.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | curl -i "http://127.0.0.1:8888/noreply" 8 | curl: (52) Empty reply from server 9 | */ 10 | static WFFacilities::WaitGroup wait_group(1); 11 | 12 | void sig_handler(int signo) 13 | { 14 | wait_group.done(); 15 | } 16 | 17 | int main() 18 | { 19 | signal(SIGINT, sig_handler); 20 | WFHttpServer server([](WFHttpTask *task) { 21 | task->set_callback([](WFHttpTask *task) { 22 | // todo : 如何查看连接已经断开 23 | // state : WFT_STATE_NOREPLY 24 | fprintf(stderr, "task finished, state = %d\n", task->get_state()); 25 | }); 26 | if (strcmp(task->get_req()->get_request_uri(), "/noreply") == 0) 27 | { 28 | task->noreply(); 29 | fprintf(stderr, "task set to no reply"); 30 | // 查看下面的resp有用吗 31 | task->get_resp()->append_output_body("server reply"); 32 | return; 33 | } 34 | else 35 | { 36 | task->get_resp()->append_output_body("server test"); 37 | return; 38 | } 39 | }); 40 | 41 | if (server.start(8888) == 0) { 42 | wait_group.wait(); 43 | server.stop(); 44 | } 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /demos/07_http/07_http_req.cc: -------------------------------------------------------------------------------- 1 | // 发起一个http请求 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace protocol; 10 | 11 | #define REDIRECT_MAX 4 12 | #define RETRY_MAX 2 13 | 14 | void http_callback(WFHttpTask *task) 15 | { 16 | HttpResponse *resp = task->get_resp(); 17 | fprintf(stderr, "Http status : %s\n", resp->get_status_code()); 18 | 19 | // response body 20 | const void *body; 21 | size_t body_len; 22 | resp->get_parsed_body(&body, &body_len); 23 | 24 | // write body to file 25 | FILE *fp = fopen("res.txt", "w"); 26 | fwrite(body, 1, body_len, fp); 27 | fclose(fp); 28 | 29 | fprintf(stderr, "write file done"); 30 | } 31 | 32 | static WFFacilities::WaitGroup wait_group(1); 33 | 34 | void sig_handler(int signo) 35 | { 36 | wait_group.done(); 37 | } 38 | 39 | int main() 40 | { 41 | signal(SIGINT, sig_handler); 42 | // logger_initConsoleLogger(stderr); 43 | // logger_setLevel(LogLevel_TRACE); 44 | std::string url = "http://www.baidu.com"; 45 | // 通过create_xxx_task创建的对象为任务,一旦创建,必须被启动或取消 46 | // 工厂函数创建的对象的生命周期均由内部管理 47 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 48 | REDIRECT_MAX, 49 | RETRY_MAX, 50 | http_callback); 51 | // 通过start,自行以task为first_task创建一个串行并理解启动任务 52 | // 任务start后,http_callback回调前,用户不能再操作该任务 53 | // 在一个task被直接或间接 dismiss/start 之后,用户不再拥有其所有权 54 | // 此后用户只能在该task的回调函数内部进行操作 55 | task->start(); 56 | // 当http_callback任务结束后,任务立即被释放 57 | wait_group.wait(); 58 | } 59 | -------------------------------------------------------------------------------- /demos/07_http/07_http_simple.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace protocol; 6 | 7 | int main() 8 | { 9 | 10 | WFHttpTask *task = 11 | WFTaskFactory::create_http_task("http://www.baidu.com", 12 | 4, 13 | 2, 14 | [](WFHttpTask *task) { 15 | HttpResponse *resp = task->get_resp(); 16 | fprintf(stderr, "Http status : %s\n", resp->get_status_code()); 17 | }); 18 | 19 | task->start(); 20 | getchar(); 21 | } 22 | -------------------------------------------------------------------------------- /demos/07_http/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(07_http_req 07_http_req.cc) 2 | target_link_libraries(07_http_req workflow) 3 | 4 | # add_executable(http_series http_series.cc) 5 | # target_link_libraries(http_series workflow spdlog::spdlog) 6 | 7 | # add_executable(http_parallel http_parallel.cc) 8 | # target_link_libraries(http_parallel workflow spdlog::spdlog) 9 | 10 | add_executable(http_echo_defer http_echo_defer.cc) 11 | target_link_libraries(http_echo_defer workflow) 12 | 13 | add_executable(07_http_no_reply 07_http_no_reply.cc) 14 | target_link_libraries(07_http_no_reply workflow) 15 | 16 | add_executable(07_http_simple 07_http_simple.cc) 17 | target_link_libraries(07_http_simple workflow) -------------------------------------------------------------------------------- /demos/07_http/http_echo_defer.cc: -------------------------------------------------------------------------------- 1 | // 让server延迟3s返回内容 2 | 3 | // server的回复时机,并不是process函数的结束,而是在server任务所在的series已经没有任务的时候。 4 | // 那么,我们只需要简单的在这个series里加入一个定时器,定时器将在process()函数之后被拉起, 5 | // 并且在定时结束之后回复请求(series已空)。 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | static WFFacilities::WaitGroup wait_group(1); 12 | 13 | int main() 14 | { 15 | WFHttpServer server([](WFHttpTask *task) { 16 | 17 | task->get_resp()->append_output_body("Hello World!"); 18 | series_of(task)->push_back(WFTaskFactory::create_timer_task(1000 * 1000, 19 | [](WFTimerTask *timer) 20 | { 21 | wait_group.done(); 22 | })); 23 | }); 24 | 25 | if (server.start(8888) == 0) 26 | { 27 | wait_group.wait(); 28 | server.stop(); 29 | } 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /demos/07_http/http_parallel.cc: -------------------------------------------------------------------------------- 1 | // 同时发起多个http请求 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace protocol; 10 | 11 | const int k_redirect_max = 4; 12 | const int k_retry_max = 2; 13 | 14 | void http_callback(WFHttpTask *task) 15 | { 16 | HttpRequest *req = task->get_req(); 17 | HttpResponse *resp = task->get_resp(); 18 | spdlog::info("req uri : {}, resp status : {}", 19 | req->get_request_uri(), resp->get_status_code()); 20 | } 21 | 22 | int main() 23 | { 24 | std::vector urls = { 25 | "http://www.baidu.com", 26 | "http://www.bing.com", 27 | "http://www.sogo.com"}; 28 | 29 | WFFacilities::WaitGroup wait_group(1); 30 | // 可以创建一个空的并行,然后通过add_series接口向并行中添加串行 31 | // 也可以在创建时指定一组串行 32 | // 并行本身也是一种任务,所以并行也可以放到串行中。 33 | // 回调函数用于通知用户该并行中的串行均已完成,不能再继续添加新的串行,且回调函数结束后,该并行会立即被销毁。 34 | ParallelWork *pwork = Workflow::create_parallel_work([&wait_group](const ParallelWork *pwork) 35 | { 36 | spdlog::info("All series in this parallel have done"); 37 | wait_group.done(); 38 | }); 39 | 40 | for (auto &url : urls) 41 | { 42 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 43 | k_redirect_max, 44 | k_retry_max, 45 | http_callback); 46 | SeriesWork *series = Workflow::create_series_work(task, nullptr); 47 | pwork->add_series(series); 48 | } 49 | // start会自动创建一个串行,并将parallel作为first_task立即开始执行 50 | pwork->start(); 51 | wait_group.wait(); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /demos/07_http/http_series.cc: -------------------------------------------------------------------------------- 1 | // 依次发起多个请求 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace protocol; 8 | 9 | void http_callback(WFHttpTask *task) 10 | { 11 | HttpRequest *req = task->get_req(); 12 | HttpResponse *resp = task->get_resp(); 13 | 14 | spdlog::info("req uri : {}, resp status : {}", 15 | req->get_request_uri(), resp->get_status_code()); 16 | } 17 | 18 | WFHttpTask *create_http_task(const std::string &url) 19 | { 20 | return WFTaskFactory::create_http_task(url, 4, 2, http_callback); 21 | } 22 | 23 | int main() 24 | { 25 | WFHttpTask *first_task = create_http_task("http://www.baidu.com"); 26 | 27 | WFFacilities::WaitGroup wait_group(1); 28 | auto series_callback = [&wait_group](const SeriesWork *series) 29 | { 30 | // series的回调函数用于通知用户该串行中的任务均已完成,不能再继续添加新的任务 31 | // 回调函数结束后,该串行会立即被销毁。 32 | spdlog::info("All tasks have done"); 33 | wait_group.done(); 34 | }; 35 | // 用户在创建时需要指定一个first_task来作为启动该series 36 | // 可选地指定一个回调函数series_callback,当所有任务执行完成后,回调函数会被调用。 37 | SeriesWork *series = Workflow::create_series_work(first_task, series_callback); 38 | series->push_back(create_http_task("http://www.bing.com")); 39 | series->push_back(create_http_task("http://www.sogo.com")); 40 | series->start(); 41 | wait_group.wait(); 42 | } -------------------------------------------------------------------------------- /demos/08_max_con/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(max_con_server server.cc) 2 | target_link_libraries(max_con_server workflow spdlog::spdlog) 3 | 4 | add_executable(max_con_client1 client01.cc) 5 | target_link_libraries(max_con_client1 workflow spdlog::spdlog) 6 | 7 | add_executable(max_con_client2 client02.cc) 8 | target_link_libraries(max_con_client2 workflow spdlog::spdlog) 9 | -------------------------------------------------------------------------------- /demos/08_max_con/client02.cc: -------------------------------------------------------------------------------- 1 | // 模拟 https://github.com/sogou/workflow/issues/135 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace protocol; 11 | 12 | const int k_redirect_max = 4; 13 | const int k_retry_max = 2; 14 | 15 | std::atomic seq; 16 | 17 | void http_callback(WFHttpTask *task) 18 | { 19 | spdlog::info("state : {}, err : {}, seq : {}", 20 | task->get_state(), task->get_error(), seq++); 21 | } 22 | 23 | int main() 24 | { 25 | std::string url = "http://127.0.0.1:8888/"; 26 | 27 | struct WFGlobalSettings settings = GLOBAL_SETTINGS_DEFAULT; 28 | settings.endpoint_params.max_connections = 1024; 29 | WORKFLOW_library_init(&settings); 30 | 31 | WFFacilities::WaitGroup wait_group(1); 32 | 33 | ParallelWork *pwork = Workflow::create_parallel_work([&wait_group](const ParallelWork *pwork) 34 | { 35 | spdlog::info("All series in this parallel have done"); 36 | wait_group.done(); 37 | }); 38 | 39 | for (int i = 0; i < 400; i++) 40 | { 41 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 42 | k_redirect_max, 43 | k_retry_max, 44 | http_callback); 45 | SeriesWork *series = Workflow::create_series_work(task, nullptr); 46 | pwork->add_series(series); 47 | } 48 | 49 | spdlog::info("client start"); 50 | pwork->start(); 51 | wait_group.wait(); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /demos/08_max_con/server.cc: -------------------------------------------------------------------------------- 1 | // 模拟 https://github.com/sogou/workflow/issues/135 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // http server端模拟慢请求,不要在process里调用sleep函数,最好使用定时器任务 16 | void process(WFHttpTask *server_task) 17 | { 18 | server_task->get_resp()->append_output_body("Hello World!"); 19 | // 延迟5秒返回的http server。等待时间不占用线程。 20 | series_of(server_task)->push_back(WFTaskFactory::create_timer_task(5 * 1000 * 1000, nullptr)); 21 | } 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | void sig_handler(int signo) 26 | { 27 | wait_group.done(); 28 | } 29 | 30 | int main() 31 | { 32 | signal(SIGINT, sig_handler); 33 | 34 | WFHttpServer server(process); 35 | uint16_t port = 8888; 36 | 37 | if (server.start(port) == 0) 38 | { 39 | spdlog::info("server start at : {}", port); 40 | wait_group.wait(); 41 | server.stop(); 42 | } 43 | else 44 | { 45 | spdlog::critical("Cannot start server"); 46 | exit(1); 47 | } 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /demos/09_timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(timer01 timer01.cc) 2 | target_link_libraries(timer01 workflow spdlog::spdlog) 3 | 4 | add_executable(timer02 timer02.cc) 5 | target_link_libraries(timer02 workflow spdlog::spdlog) 6 | -------------------------------------------------------------------------------- /demos/09_timer/timer01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static WFFacilities::WaitGroup wait_group(1); 6 | 7 | void callback(WFHttpTask *task) 8 | { 9 | const void *body; 10 | size_t size; 11 | 12 | if (task->get_resp()->get_parsed_body(&body, &size)) 13 | fwrite(body, 1, size, stdout); 14 | 15 | WFTimerTask *timer = WFTaskFactory::create_timer_task(1000 * 1000, [](WFTimerTask *timer) 16 | { 17 | spdlog::info("Timer ends."); 18 | wait_group.done(); 19 | }); 20 | series_of(task)->push_back(timer); 21 | spdlog::info("Wait for 1 second..."); // timer不阻塞,先执行 22 | } 23 | 24 | int main(void) 25 | { 26 | WFHttpTask *task = WFTaskFactory::create_http_task("http://www.baidu.com/", 3, 2, callback); 27 | task->start(); 28 | wait_group.wait(); 29 | return 0; 30 | } -------------------------------------------------------------------------------- /demos/09_timer/timer02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | WFFacilities::WaitGroup wait_group(1); 9 | auto start = std::chrono::high_resolution_clock::now(); 10 | WFTimerTask *task = WFTaskFactory::create_timer_task(10 * 1000, 11 | [&start, &wait_group](WFTimerTask *timer) 12 | { 13 | auto end = std::chrono::high_resolution_clock::now(); 14 | std::chrono::duration tm = end - start; 15 | fprintf(stderr, "time consume : %f ms\n", tm.count()); 16 | wait_group.done(); 17 | }); 18 | 19 | task->start(); 20 | wait_group.wait(); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /demos/10_http_forward/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(forward forward.cc) 2 | target_link_libraries(forward workflow spdlog::spdlog) 3 | 4 | -------------------------------------------------------------------------------- /demos/10_http_forward/forward.cc: -------------------------------------------------------------------------------- 1 | // 转发服务器的构建和series上下文的使用 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace protocol; 9 | 10 | void callback(WFHttpTask *client_task) 11 | { 12 | HttpResponse *resp = client_task->get_resp(); 13 | const void *body; 14 | size_t size; 15 | 16 | if (resp->get_parsed_body(&body, &size)) 17 | resp->append_output_body_nocopy(body, size); 18 | 19 | SeriesWork *series = series_of(client_task); 20 | WFHttpTask *server_task = static_cast(series->get_context()); 21 | *server_task->get_resp() = std::move(*resp); 22 | } 23 | 24 | void process(WFHttpTask *server_task) 25 | { 26 | HttpRequest *req = server_task->get_req(); 27 | std::string url("http://www.baidu.com"); 28 | url = url + req->get_request_uri(); 29 | 30 | // 向series里push_back一个http client任务,并且把这个http任务返回的结果写进server的回复消息 31 | WFHttpTask *client_task = WFTaskFactory::create_http_task(url, 3, 2, callback); 32 | *client_task->get_req() = std::move(*req); // 把req转发给后端 33 | client_task->get_req()->set_header_pair("Host", "www.baidu.com"); // 少这个会403 forbidden 34 | 35 | SeriesWork *series = series_of(server_task); 36 | // 每个运行中的任务一点处于某个任务流(series)里,同一个series上的任务,可以通过series context共享上下文。 37 | // series上下文用来存放server task, 以便在client任务完成之后填写回复消息 38 | series->set_context(server_task); 39 | series->push_back(client_task); 40 | } 41 | 42 | static WFFacilities::WaitGroup wait_group(1); 43 | 44 | void sig_handler(int signo) 45 | { 46 | wait_group.done(); 47 | } 48 | 49 | int main() 50 | { 51 | signal(SIGINT, sig_handler); 52 | WFHttpServer server(process); 53 | 54 | if (server.start(8888) == 0) 55 | { 56 | wait_group.wait(); 57 | server.stop(); 58 | } 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /demos/11_life_cycle/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(life life.cc) 2 | target_link_libraries(life workflow spdlog::spdlog) 3 | 4 | -------------------------------------------------------------------------------- /demos/12_counter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(counter_intro counter_intro.cc) 2 | target_link_libraries(counter_intro workflow spdlog::spdlog) 3 | 4 | add_executable(counter_to_parallel counter_to_parallel.cc) 5 | target_link_libraries(counter_to_parallel workflow spdlog::spdlog) 6 | 7 | -------------------------------------------------------------------------------- /demos/12_counter/counter_intro.cc: -------------------------------------------------------------------------------- 1 | // 计数器是我们框架中一种非常重要的基础任务,计数器本质上是一个不占线程的信号量。 2 | // 计数器主要用于工作流的控制,包括匿名计数器和命名计数器两种,可以实现非常复杂的业务逻辑。 3 | 4 | // 每个计数器都包含一个target_value,当计数器的计数到达target_value,callback被调用。 5 | // 匿名计数器直接通过WFCounterTask的count方法来增加计数 6 | // 命名计数器,可以通过count, count_by_name函数来增加计数 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() 16 | { 17 | const int cnt = 3; 18 | WFFacilities::WaitGroup wait_group(1); 19 | WFCounterTask *counter = 20 | WFTaskFactory::create_counter_task("counter", 21 | cnt, 22 | [&wait_group](WFCounterTask *counter) 23 | { 24 | spdlog::info("counter callback"); 25 | wait_group.done(); 26 | }); 27 | 28 | counter->count(); 29 | counter->start(); 30 | spdlog::info("counter start"); 31 | WFTaskFactory::count_by_name("counter"); 32 | WFTaskFactory::count_by_name("counter", 1); 33 | wait_group.wait(); 34 | } -------------------------------------------------------------------------------- /demos/13_block_series/block_series.cc: -------------------------------------------------------------------------------- 1 | // https://github.com/sogou/workflow/issues/301 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace protocol; 13 | 14 | const std::string k_counter_name = "counter"; 15 | 16 | class BlockSeries 17 | { 18 | public: 19 | BlockSeries(SubTask *first, const std::string &name) : counter_name_(name) 20 | { 21 | series_ = Workflow::create_series_work(first, [](const SeriesWork *series) 22 | { spdlog::info("series done"); }); 23 | WFCounterTask *counter = WFTaskFactory::create_counter_task(counter_name_, 1, nullptr); 24 | series_->push_back(counter); 25 | } 26 | 27 | ~BlockSeries() 28 | { 29 | // 假设用户已经调用过start() 30 | WFTaskFactory::count_by_name(counter_name_); 31 | } 32 | 33 | void start() 34 | { 35 | series_->start(); 36 | } 37 | 38 | void push_back(SubTask *task) 39 | { 40 | { 41 | std::lock_guard lock(mutex_); 42 | // 我实际添加了两个任务,为保证这两个任务中间不被打断,必须加锁 43 | WFCounterTask *counter = WFTaskFactory::create_counter_task(counter_name_, 1, nullptr); 44 | series_->push_back(task); // 这里的push_back本来就是加了锁的 45 | series_->push_back(counter); 46 | } 47 | // 这个counter_by_name打开的是上一个push_back添加的counter。 48 | WFTaskFactory::count_by_name(counter_name_); 49 | } 50 | 51 | private: 52 | SeriesWork *series_; 53 | std::string counter_name_; 54 | std::mutex mutex_; 55 | }; 56 | 57 | int main() 58 | { 59 | // todo : 找一个合适的demo 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /demos/14_restful/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(restful_server restful_server.cc base64.cc) 2 | target_link_libraries(restful_server workflow spdlog::spdlog) 3 | 4 | add_executable(restful_client restful_client.cc) 5 | target_link_libraries(restful_client workflow spdlog::spdlog) 6 | -------------------------------------------------------------------------------- /demos/14_restful/base64.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved 4 | * 5 | **************************************************************************/ 6 | 7 | 8 | #ifndef __ABASE64_H_ 9 | #define __ABASE64_H_ 10 | 11 | #include 12 | #include 13 | 14 | 15 | std::string base64_encode(unsigned char const* , unsigned int len); 16 | std::string base64_decode(std::string const& s); 17 | 18 | 19 | #endif //__BASE64_H_ -------------------------------------------------------------------------------- /demos/14_restful/encode.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::string url_encode(const std::string &value) { 7 | std::ostringstream escaped; 8 | escaped.fill('0'); 9 | escaped << std::hex; 10 | 11 | for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { 12 | std::string::value_type c = (*i); 13 | 14 | // Keep alphanumeric and other accepted characters intact 15 | if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { 16 | escaped << c; 17 | continue; 18 | } 19 | 20 | // Any other characters are percent-encoded 21 | escaped << std::uppercase; 22 | escaped << '%' << std::setw(2) << int((unsigned char) c); 23 | escaped << std::nouppercase; 24 | } 25 | 26 | return escaped.str(); 27 | } -------------------------------------------------------------------------------- /demos/14_restful/readme.md: -------------------------------------------------------------------------------- 1 | ## tutorial 2 | 3 | https://zhuanlan.zhihu.com/p/412221224 -------------------------------------------------------------------------------- /demos/14_restful/restful.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import base64 3 | 4 | ''' 5 | 红酒识别 6 | ''' 7 | request_url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/redwine" 8 | # 二进制方式打开图片文件 9 | f = open('./wine.jpg', 'rb') 10 | img = base64.b64encode(f.read()) 11 | 12 | print(img) 13 | 14 | params = {"image":img} 15 | access_token = '[token]' 16 | request_url = request_url + "?access_token=" + access_token 17 | headers = {'content-type': 'application/x-www-form-urlencoded'} 18 | response = requests.post(request_url, data=params, headers=headers) 19 | if response: 20 | print(response.json()) -------------------------------------------------------------------------------- /demos/14_restful/wine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/demos/14_restful/wine.jpg -------------------------------------------------------------------------------- /demos/15_file/15_file_write.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace protocol; 9 | 10 | // in server can respond to client we save the file 11 | // void pwrite_callback(WFFileIOTask *task) 12 | // { 13 | // long ret = task->get_retval(); 14 | // HttpResponse *resp = (HttpResponse *)task->user_data; 15 | 16 | // if (task->get_state() != WFT_STATE_SUCCESS || ret < 0) 17 | // { 18 | // resp->set_status_code("503"); 19 | // resp->append_output_body("503 Internal Server Error.\r\n"); 20 | // } 21 | // else 22 | // { 23 | // resp->set_status_code("200"); 24 | // resp->append_output_body("200 success.\r\n"); 25 | // } 26 | // } 27 | 28 | void pwrite_callback(WFFileIOTask *task) 29 | { 30 | fprintf(stderr, "write finish"); 31 | } 32 | 33 | static WFFacilities::WaitGroup wait_group(1); 34 | 35 | void sig_handler(int signo) 36 | { 37 | wait_group.done(); 38 | } 39 | 40 | int main() 41 | { 42 | signal(SIGINT, sig_handler); 43 | 44 | std::string content = "111111111111112222222222222222223333333333330"; 45 | 46 | std::string path = "./demo.txt"; 47 | 48 | WFFileIOTask *pwrite_task = WFTaskFactory::create_pwrite_task(path, 49 | static_cast(content.c_str()), 50 | content.size(), 51 | 0, 52 | pwrite_callback); 53 | 54 | pwrite_task->start(); 55 | 56 | wait_group.wait(); 57 | } 58 | -------------------------------------------------------------------------------- /demos/15_file/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(15_file_server_01 15_file_server_01.cc) 2 | target_link_libraries(15_file_server_01 workflow) 3 | 4 | add_executable(15_file_server_02 15_file_server_02.cc) 5 | target_link_libraries(15_file_server_02 workflow) 6 | 7 | add_executable(15_file_write 15_file_write.cc) 8 | target_link_libraries(15_file_write workflow) 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demos/16_graph/16_graph_02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace protocol; 6 | 7 | // https://github.com/sogou/workflow/issues/607 8 | 9 | static WFFacilities::WaitGroup wait_group(1); 10 | 11 | void sig_handler(int signo) 12 | { 13 | wait_group.done(); 14 | } 15 | 16 | void http_callback(WFHttpTask *http_task) 17 | { 18 | HttpResponse *resp = http_task->get_resp(); 19 | 20 | const void *body; 21 | size_t body_len; 22 | resp->get_parsed_body(&body, &body_len); 23 | fprintf(stderr, "body len : %zu\n", body_len); 24 | } 25 | 26 | int main() 27 | { 28 | signal(SIGINT, sig_handler); 29 | WFHttpServer server([](WFHttpTask *server_task) { 30 | WFGraphTask *graph = WFTaskFactory::create_graph_task([](const WFGraphTask *){ 31 | fprintf(stderr, "graph callback"); 32 | }); 33 | 34 | auto http_task_01 = WFTaskFactory::create_http_task("http://www.baidu.com", 4, 2, http_callback); 35 | auto http_task_02 = WFTaskFactory::create_http_task("http://www.bing.com", 4, 2, http_callback); 36 | WFGraphNode& http_node_01 = graph->create_graph_node(http_task_01); 37 | WFGraphNode& http_node_02 = graph->create_graph_node(http_task_02); 38 | // http_node_01-->http_node_02; // 没有这句话就是没边 --> 并行 39 | 40 | **server_task << graph; 41 | }); 42 | 43 | if (server.start(8888) == 0) { 44 | wait_group.wait(); 45 | server.stop(); 46 | } 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /demos/16_graph/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(16_graph_00 16_graph_00.cc) 2 | target_link_libraries(16_graph_00 workflow) 3 | 4 | add_executable(16_graph_01 16_graph_01.cc) 5 | target_link_libraries(16_graph_01 workflow) 6 | 7 | add_executable(16_graph_02 16_graph_02.cc) 8 | target_link_libraries(16_graph_02 workflow) 9 | -------------------------------------------------------------------------------- /demos/17_go_task/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(go go.cc) 2 | target_link_libraries(go workflow) 3 | 4 | add_executable(go_simple go_simple.cc) 5 | target_link_libraries(go_simple workflow) 6 | 7 | -------------------------------------------------------------------------------- /demos/17_go_task/go_simple.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Factorial(int n, protocol::HttpResponse *resp) 4 | { 5 | unsigned long long factorial = 1; 6 | for(int i = 1; i <= n; i++) 7 | { 8 | factorial *= i; 9 | } 10 | resp->append_output_body(std::to_string(factorial)); 11 | } 12 | 13 | void process(WFHttpTask *server_task) 14 | { 15 | const char *uri = server_task->get_req()->get_request_uri(); 16 | if (*uri == '/') 17 | uri++; 18 | int n = atoi(uri); 19 | protocol::HttpResponse *resp = server_task->get_resp(); 20 | WFGoTask *go_task = WFTaskFactory::create_go_task("go", Factorial, n, resp); 21 | **server_task << go_task; 22 | } 23 | 24 | int main() 25 | { 26 | WFHttpServer server(process); 27 | 28 | if (server.start(8888) == 0) 29 | { 30 | getchar(); 31 | server.stop(); 32 | } 33 | return 0; 34 | } -------------------------------------------------------------------------------- /demos/18_con_ctx/ctx.cc: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/sogou/workflow/blob/master/docs/about-connection-context.md 3 | 4 | 需要维护连接状态的,我们需要把一段上下文和连接绑定。 5 | 6 | http协议可以说是一种完全无连接状态的协议,http会话,是通过cookie来实现的 7 | 8 | 一般情况下只有server任务需要使用连接上下文,并且只需要在process函数内部使用,这也是最安全最简单的用法 9 | 10 | 任务在callback里也可以使用或修改连接上下文,只是使用的时候需要考虑并发的问题 11 | */ 12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/19_parallel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(get_all_para get_all_para.cc) 2 | target_link_libraries(get_all_para workflow spdlog::spdlog) 3 | 4 | -------------------------------------------------------------------------------- /demos/20_dynamic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(dynamic dynamic.cc) 2 | target_link_libraries(dynamic workflow spdlog::spdlog) 3 | 4 | -------------------------------------------------------------------------------- /demos/20_dynamic/dynamic.cc: -------------------------------------------------------------------------------- 1 | // WFDynamicTask,通过一个函数在它实际启动的时候再生成具体的task。 2 | // 可以把一切任务变成动态创建,避免callback 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | WFFacilities::WaitGroup wait_group(1); 9 | 10 | SubTask *func(WFDynamicTask *) 11 | { 12 | std::string url; 13 | std::cin >> url; 14 | return WFTaskFactory::create_http_task(url, 3, 0, [](WFHttpTask *task) { 15 | const void *body; 16 | size_t size; 17 | 18 | if (task->get_resp()->get_parsed_body(&body, &size)) 19 | std::cout << static_cast(body); 20 | 21 | wait_group.done(); 22 | }); 23 | } 24 | 25 | int main() 26 | { 27 | WFDynamicTask *t = WFTaskFactory::create_dynamic_task(func); 28 | t->start(); 29 | wait_group.wait(); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /demos/21_cmp/21_clent01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace protocol; 8 | 9 | std::atomic seq{0}; 10 | 11 | void http_callback(WFHttpTask *task) 12 | { 13 | HttpRequest *req = task->get_req(); 14 | HttpResponse *resp = task->get_resp(); 15 | req->add_header_pair("Connection", "Keep-Alive"); 16 | const void* body; 17 | size_t body_len; 18 | resp->get_parsed_body(&body, &body_len); 19 | fprintf(stderr, "seq : %d, body : %s\n", seq++, static_cast(body)); 20 | } 21 | 22 | WFHttpTask *create_http_task(const std::string &url) 23 | { 24 | return WFTaskFactory::create_http_task(url, 4, 2, http_callback); 25 | } 26 | 27 | int main() 28 | { 29 | WFHttpTask *first_task = create_http_task("http://127.0.0.1:8888"); 30 | 31 | WFFacilities::WaitGroup wait_group(1); 32 | auto series_callback = [&wait_group](const SeriesWork *series) 33 | { 34 | fprintf(stderr, "all one\n"); 35 | wait_group.done(); 36 | }; 37 | SeriesWork *series = Workflow::create_series_work(first_task, series_callback); 38 | for(int i = 0; i < 100000; i++) { 39 | series->push_back(create_http_task("http://127.0.0.1:8888")); 40 | } 41 | series->start(); 42 | wait_group.wait(); 43 | } -------------------------------------------------------------------------------- /demos/21_cmp/21_client02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace protocol; 8 | 9 | const int k_redirect_max = 4; 10 | const int k_retry_max = 2; 11 | 12 | void http_callback(WFHttpTask *task) 13 | { 14 | HttpRequest *req = task->get_req(); 15 | HttpResponse *resp = task->get_resp(); 16 | spdlog::info("req uri : {}, resp status : {}", 17 | req->get_request_uri(), resp->get_status_code()); 18 | } 19 | 20 | int main() 21 | { 22 | WFFacilities::WaitGroup wait_group(1); 23 | ParallelWork *pwork = Workflow::create_parallel_work([&wait_group](const ParallelWork *pwork) 24 | { 25 | fprintf(stderr, "All series in this parallel have done"); 26 | wait_group.done(); 27 | }); 28 | 29 | for (auto &url : urls) 30 | { 31 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 32 | k_redirect_max, 33 | k_retry_max, 34 | http_callback); 35 | SeriesWork *series = Workflow::create_series_work(task, nullptr); 36 | pwork->add_series(series); 37 | } 38 | // start会自动创建一个串行,并将parallel作为first_task立即开始执行 39 | pwork->start(); 40 | wait_group.wait(); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /demos/21_cmp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(21_clent01 21_clent01.cc) 2 | target_link_libraries(21_clent01 workflow) 3 | 4 | add_executable(test_add_header02 test02.cc) 5 | target_link_libraries(test_add_header02 workflow) 6 | 7 | add_executable(21_server 21_server.cc) 8 | target_link_libraries(21_server workflow) -------------------------------------------------------------------------------- /demos/21_cmp/test02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace protocol; 9 | 10 | #define REDIRECT_MAX 4 11 | #define RETRY_MAX 2 12 | 13 | void http_callback(WFHttpTask *task) 14 | { 15 | HttpRequest *req = task->get_req(); 16 | HttpResponse *resp = task->get_resp(); 17 | // cmp here 18 | // req->add_header_pair("Connection", "Keep-Alive"); 19 | 20 | const void *body; 21 | size_t body_len; 22 | resp->get_parsed_body(&body, &body_len); 23 | 24 | std::cout << "end" << std::endl; 25 | } 26 | 27 | static WFFacilities::WaitGroup wait_group(1); 28 | 29 | void sig_handler(int signo) 30 | { 31 | wait_group.done(); 32 | } 33 | 34 | int main() 35 | { 36 | signal(SIGINT, sig_handler); 37 | std::string url = "http://www.baidu.com"; 38 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 39 | REDIRECT_MAX, 40 | RETRY_MAX, 41 | http_callback); 42 | task->start(); 43 | wait_group.wait(); 44 | } 45 | -------------------------------------------------------------------------------- /demos/22_dns/22_dns_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static WFFacilities::WaitGroup wait_group(1); 6 | 7 | void sig_handler(int signo) 8 | { 9 | wait_group.done(); 10 | } 11 | 12 | int main() { 13 | 14 | unsigned short req_id = 0x4321; 15 | WFFacilities::WaitGroup wait_group(1); 16 | WFDnsClient client; 17 | 18 | client.init("dns://119.29.29.29/"); 19 | 20 | auto *task = client.create_dns_task("www.sogou.com", 21 | [&wait_group, req_id] (WFDnsTask *task) 22 | { 23 | int state = task->get_state(); 24 | 25 | if (state == WFT_STATE_SUCCESS) 26 | { 27 | unsigned short resp_id = task->get_resp()->get_id(); 28 | if(req_id == resp_id) { 29 | fprintf(stderr, "id equals\n"); 30 | } 31 | } 32 | wait_group.done(); 33 | }); 34 | 35 | client.deinit(); 36 | 37 | auto *req = task->get_req(); 38 | req->set_id(req_id); 39 | task->start(); 40 | 41 | wait_group.wait(); 42 | } 43 | -------------------------------------------------------------------------------- /demos/22_dns/22_dns_02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static WFFacilities::WaitGroup wait_group(1); 8 | static const int INET_ADDR_LEN = 128; 9 | 10 | void sig_handler(int signo) 11 | { 12 | wait_group.done(); 13 | } 14 | 15 | std::string ip_bin_to_str(void* sa_sin_addr) 16 | { 17 | struct sockaddr_in sa; 18 | char str[INET_ADDR_LEN]; 19 | inet_ntop(AF_INET, sa_sin_addr, str, INET_ADDR_LEN); 20 | return str; 21 | } 22 | 23 | int main() 24 | { 25 | signal(SIGINT, sig_handler); 26 | std::string url = "dns://119.29.29.29/www.baidu.com"; 27 | 28 | auto *task = WFTaskFactory::create_dns_task(url, 4, 29 | [](WFDnsTask *task) 30 | { 31 | auto dns_resp = task->get_resp(); 32 | DnsResultCursor cursor(dns_resp); 33 | dns_record *record = nullptr; 34 | while (cursor.next(&record)) 35 | { 36 | if (record->type == DNS_TYPE_A) 37 | { 38 | fprintf(stderr, "ipv4 : %s\n", ip_bin_to_str(record->rdata).c_str()); 39 | } 40 | else if(record->type == DNS_TYPE_AAAA) 41 | { 42 | fprintf(stderr, "ipv6 : %s\n", ip_bin_to_str(record->rdata).c_str()); 43 | } 44 | } 45 | fprintf(stderr, "dns done"); 46 | }); 47 | task->start(); 48 | wait_group.wait(); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /demos/22_dns/22_dns_05.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static WFFacilities::WaitGroup wait_group(1); 8 | static const int INET_ADDR_LEN = 128; 9 | 10 | 11 | // 获取ipv6 12 | 13 | void sig_handler(int signo) 14 | { 15 | wait_group.done(); 16 | } 17 | 18 | std::string ip_bin_to_str(void* sa_sin_addr, bool ipv4 = true) 19 | { 20 | struct sockaddr_in sa; 21 | char str[INET_ADDR_LEN]; 22 | if(ipv4) 23 | inet_ntop(AF_INET, sa_sin_addr, str, INET_ADDR_LEN); 24 | else 25 | inet_ntop(AF_INET6, sa_sin_addr, str, INET_ADDR_LEN); 26 | return str; 27 | } 28 | 29 | int main() 30 | { 31 | signal(SIGINT, sig_handler); 32 | std::string url = "dns://8.8.8.8/ipv6.tsinghua.edu.cn"; 33 | 34 | auto *task = WFTaskFactory::create_dns_task(url, 4, 35 | [](WFDnsTask *task) 36 | { 37 | auto dns_resp = task->get_resp(); 38 | DnsResultCursor cursor(dns_resp); 39 | dns_record *record = nullptr; 40 | while (cursor.next(&record)) 41 | { 42 | if (record->type == DNS_TYPE_A) 43 | { 44 | fprintf(stderr, "ipv4 : %s\n", ip_bin_to_str(record->rdata).c_str()); 45 | } 46 | else if(record->type == DNS_TYPE_AAAA) 47 | { 48 | fprintf(stderr, "ipv6 : %s\n", ip_bin_to_str(record->rdata, false).c_str()); 49 | } 50 | } 51 | fprintf(stderr, "dns done\n"); 52 | }); 53 | 54 | task->get_req()->set_question_type(DNS_TYPE_AAAA); // 只需要 set_question_type 即可 55 | 56 | task->start(); 57 | wait_group.wait(); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /demos/22_dns/22_dns_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace protocol; 8 | 9 | void process(WFDnsTask *dns_task) 10 | { 11 | DnsRequest *req = dns_task->get_req(); 12 | DnsResponse *resp = dns_task->get_resp(); 13 | 14 | } 15 | 16 | static WFFacilities::WaitGroup wait_group(1); 17 | 18 | void sig_handler(int signo) 19 | { 20 | wait_group.done(); 21 | } 22 | 23 | int main() 24 | { 25 | signal(SIGINT, sig_handler); 26 | 27 | WFDnsServer server(process); 28 | uint16_t port = 8888; 29 | 30 | if (server.start(port) == 0) 31 | { 32 | wait_group.wait(); 33 | server.stop(); // 关停是非暴力式的,会等待正在服务的请求执行完。 34 | } 35 | else 36 | { 37 | fprintf(stderr, "Cannot start server"); 38 | exit(1); 39 | } 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /demos/22_dns/22_resolver_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int main() { 5 | 6 | } -------------------------------------------------------------------------------- /demos/22_dns/22_test_dns_cache.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | // 通过本例分析 8 | // https://github.com/sogou/workflow/commit/1736d64d91c8b54c533a6e949354bee5566d6e2c 9 | 10 | using namespace protocol; 11 | 12 | void http_callback(WFHttpTask *task) 13 | { 14 | HttpRequest *req = task->get_req(); 15 | HttpResponse *resp = task->get_resp(); 16 | fprintf(stderr, "req uri : %s, resp status : %s\n", 17 | req->get_request_uri(), resp->get_status_code()); 18 | } 19 | 20 | WFHttpTask *create_http_task(const std::string &url) 21 | { 22 | return WFTaskFactory::create_http_task(url, 4, 2, http_callback); 23 | } 24 | 25 | int main() 26 | { 27 | std::vector url_list = { 28 | "http://www.bing.com", 29 | "http://www.tencent.com", 30 | "http://www.sogou.com", 31 | "http://www.baidu.com", 32 | }; 33 | 34 | WFHttpTask *first_task = create_http_task("http://www.baidu.com"); 35 | 36 | WFFacilities::WaitGroup wait_group(1); 37 | auto series_callback = [&wait_group](const SeriesWork *series) 38 | { 39 | fprintf(stderr, "All tasks have done"); 40 | wait_group.done(); 41 | }; 42 | SeriesWork *series = Workflow::create_series_work(first_task, series_callback); 43 | for(int i = 0; i < 5; i++) 44 | { 45 | for(auto& url : url_list) 46 | { 47 | series->push_back(create_http_task(url)); 48 | } 49 | } 50 | series->start(); 51 | wait_group.wait(); 52 | } -------------------------------------------------------------------------------- /demos/22_dns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(22_dns_01 22_dns_01.cc) 2 | target_link_libraries(22_dns_01 workflow) 3 | 4 | add_executable(22_dns_02 22_dns_02.cc) 5 | target_link_libraries(22_dns_02 workflow) 6 | 7 | add_executable(22_dns_03 22_dns_03.cc) 8 | target_link_libraries(22_dns_03 workflow) 9 | 10 | add_executable(22_dns_04 22_dns_04.cc) 11 | target_link_libraries(22_dns_04 workflow) 12 | 13 | add_executable(22_dns_05 22_dns_05.cc) 14 | target_link_libraries(22_dns_05 workflow) 15 | 16 | add_executable(22_test_dns_cache 22_test_dns_cache.cc) 17 | target_link_libraries(22_test_dns_cache workflow) 18 | 19 | -------------------------------------------------------------------------------- /demos/23_list/23_list_01_init.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | 3 | // init demo 4 | 5 | struct Task 6 | { 7 | struct list_head entry_list; 8 | int val; 9 | }; 10 | 11 | int main() 12 | { 13 | struct Task task; 14 | INIT_LIST_HEAD(&task.entry_list); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /demos/23_list/23_list_02_add.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_add demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | void list_add_test() 14 | { 15 | struct Task task; 16 | INIT_LIST_HEAD(&task.entry_list); 17 | struct list_head *pos; 18 | for(int i = 0; i < 4; i++) 19 | { 20 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 21 | t->val = i; 22 | list_add(&t->entry_list, &task.entry_list); 23 | } 24 | // 3 - 2 - 1 - 0 25 | list_for_each(pos, &task.entry_list) 26 | { 27 | printf("val = %d\n", ((struct Task*)pos)->val); 28 | } 29 | } 30 | 31 | void list_tail_test() 32 | { 33 | struct Task task; 34 | INIT_LIST_HEAD(&task.entry_list); 35 | struct list_head *pos; 36 | for(int i = 0; i < 4; i++) 37 | { 38 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 39 | t->val = i; 40 | list_add_tail(&t->entry_list, &task.entry_list); 41 | } 42 | // 0 - 1 - 2 - 3 43 | list_for_each(pos, &task.entry_list) 44 | { 45 | printf("val = %d\n", ((struct Task*)pos)->val); 46 | } 47 | } 48 | 49 | int main() 50 | { 51 | printf("list_add_test : \n"); 52 | list_add_test(); 53 | 54 | printf("list_tail_test : \n"); 55 | list_tail_test(); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /demos/23_list/23_list_03_del.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_del demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | int main() 14 | { 15 | struct Task task; 16 | INIT_LIST_HEAD(&task.entry_list); 17 | struct list_head *pos; 18 | for(int i = 0; i < 4; i++) 19 | { 20 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 21 | t->val = i; 22 | list_add(&t->entry_list, &task.entry_list); 23 | } 24 | // 3 - 2 - 1 - 0 25 | list_for_each(pos, &task.entry_list) 26 | { 27 | printf("val = %d\n", ((struct Task*)pos)->val); 28 | } 29 | 30 | struct Task *task_pos; 31 | list_for_each_entry(task_pos, &task.entry_list, entry_list) 32 | { 33 | if (task_pos->val == 2) 34 | { 35 | list_del(&task_pos->entry_list); 36 | break; 37 | } 38 | } 39 | 40 | printf("After del : \n"); 41 | // 3 - 1 - 0 42 | list_for_each(pos, &task.entry_list) 43 | { 44 | printf("val = %d\n", ((struct Task*)pos)->val); 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /demos/23_list/23_list_04_move.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_move demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | int main() 14 | { 15 | struct Task task1; 16 | INIT_LIST_HEAD(&task1.entry_list); 17 | 18 | struct Task task2; 19 | INIT_LIST_HEAD(&task2.entry_list); 20 | 21 | struct list_head *pos; 22 | for(int i = 0; i < 4; i++) 23 | { 24 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 25 | t->val = i; 26 | list_add(&t->entry_list, &task1.entry_list); 27 | } 28 | 29 | for(int i = 4; i < 8; i++) 30 | { 31 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 32 | t->val = i; 33 | list_add(&t->entry_list, &task2.entry_list); 34 | } 35 | 36 | struct Task *task_pos; 37 | list_for_each_entry(task_pos, &task1.entry_list, entry_list) 38 | { 39 | if (task_pos->val == 2) 40 | { 41 | list_move(&task_pos->entry_list, &task2.entry_list); 42 | break; 43 | } 44 | } 45 | 46 | printf("First link : \n"); 47 | // 3 - 1 - 0 48 | list_for_each(pos, &task1.entry_list) 49 | { 50 | printf("val = %d\n", ((struct Task*)pos)->val); 51 | } 52 | printf("Second link : \n"); 53 | // 2 - 7 - 6 - 5 - 4 54 | list_for_each(pos, &task2.entry_list) 55 | { 56 | printf("val = %d\n", ((struct Task*)pos)->val); 57 | } 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /demos/23_list/23_list_05_splice.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_splice demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | int main() 14 | { 15 | struct Task task1; 16 | INIT_LIST_HEAD(&task1.entry_list); 17 | 18 | struct Task task2; 19 | INIT_LIST_HEAD(&task2.entry_list); 20 | 21 | struct list_head *pos; 22 | for(int i = 0; i < 4; i++) 23 | { 24 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 25 | t->val = i; 26 | list_add(&t->entry_list, &task1.entry_list); 27 | } 28 | 29 | for(int i = 4; i < 8; i++) 30 | { 31 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 32 | t->val = i; 33 | list_add(&t->entry_list, &task2.entry_list); 34 | } 35 | 36 | printf("First link : \n"); 37 | // 3 - 2 - 1 - 0 38 | list_for_each(pos, &task1.entry_list) 39 | { 40 | printf("val = %d\n", ((struct Task*)pos)->val); 41 | } 42 | printf("Second link : \n"); 43 | // 7 - 6 - 5 - 4 44 | list_for_each(pos, &task2.entry_list) 45 | { 46 | printf("val = %d\n", ((struct Task*)pos)->val); 47 | } 48 | printf("After join two linklist : \n"); 49 | list_splice(&task1.entry_list, &task2.entry_list); 50 | 51 | // infinite loop here 52 | // list_for_each(pos, &task1.entry_list) 53 | // { 54 | // printf("val = %d\n", ((struct Task*)pos)->val); 55 | // } 56 | // printf("Second link : \n"); 57 | 58 | // 3 - 2 - 1 - 0 - 7 - 6 - 5 - 4 59 | list_for_each(pos, &task2.entry_list) 60 | { 61 | printf("val = %d\n", ((struct Task*)pos)->val); 62 | } 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /demos/23_list/23_list_05_splice_init.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_splice demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | int main() 14 | { 15 | struct Task task1; 16 | INIT_LIST_HEAD(&task1.entry_list); 17 | 18 | struct Task task2; 19 | INIT_LIST_HEAD(&task2.entry_list); 20 | 21 | struct list_head *pos; 22 | for(int i = 0; i < 4; i++) 23 | { 24 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 25 | t->val = i; 26 | list_add(&t->entry_list, &task1.entry_list); 27 | } 28 | 29 | for(int i = 4; i < 8; i++) 30 | { 31 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 32 | t->val = i; 33 | list_add(&t->entry_list, &task2.entry_list); 34 | } 35 | 36 | printf("First link : \n"); 37 | // 3 - 2 - 1 - 0 38 | list_for_each(pos, &task1.entry_list) 39 | { 40 | printf("val = %d\n", ((struct Task*)pos)->val); 41 | } 42 | printf("Second link : \n"); 43 | // 7 - 6 - 5 - 4 44 | list_for_each(pos, &task2.entry_list) 45 | { 46 | printf("val = %d\n", ((struct Task*)pos)->val); 47 | } 48 | printf("After join two linklist : \n"); 49 | list_splice_init(&task1.entry_list, &task2.entry_list); 50 | 51 | printf("Second link init: \n"); 52 | list_for_each(pos, &task1.entry_list) 53 | { 54 | printf("val = %d\n", ((struct Task*)pos)->val); 55 | } 56 | printf("Second link : \n"); 57 | 58 | // 3 - 2 - 1 - 0 - 7 - 6 - 5 - 4 59 | list_for_each(pos, &task2.entry_list) 60 | { 61 | printf("val = %d\n", ((struct Task*)pos)->val); 62 | } 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /demos/23_list/24_06_list_traverse.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | 5 | // list_del demo 6 | 7 | struct Task 8 | { 9 | struct list_head entry_list; 10 | int val; 11 | }; 12 | 13 | int main() 14 | { 15 | struct Task task; 16 | INIT_LIST_HEAD(&task.entry_list); 17 | struct list_head *pos; 18 | for(int i = 0; i < 4; i++) 19 | { 20 | struct Task *t = (struct Task *)malloc(sizeof(struct Task)); 21 | t->val = i; 22 | list_add(&t->entry_list, &task.entry_list); 23 | } 24 | // 3 - 2 - 1 - 0 25 | list_for_each(pos, &task.entry_list) 26 | { 27 | printf("val = %d\n", ((struct Task*)pos)->val); 28 | } 29 | 30 | struct Task *task_pos; 31 | list_for_each_entry(task_pos, &task.entry_list, entry_list) 32 | { 33 | if (task_pos->val == 2) 34 | { 35 | list_del(&task_pos->entry_list); 36 | break; 37 | } 38 | } 39 | 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /demos/23_list/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(23_list_01 23_list_01.cc) 2 | target_link_libraries(23_list_01 workflow) 3 | 4 | -------------------------------------------------------------------------------- /demos/24_thrd_task/24_thrd_task_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // 直接定义thread_task三要素 6 | 7 | // 定义INPUT 8 | struct AddInput 9 | { 10 | int x; 11 | int y; 12 | }; 13 | 14 | // 定义OUTPUT 15 | struct AddOutput 16 | { 17 | int res; 18 | }; 19 | 20 | // 加法流程 21 | void add_routine(const AddInput *input, AddOutput *output) 22 | { 23 | output->res = input->x + input->y; 24 | } 25 | 26 | using AddTask = WFThreadTask; 27 | 28 | void callback(AddTask *task) 29 | { 30 | auto *input = task->get_input(); 31 | auto *output = task->get_output(); 32 | 33 | assert(task->get_state() == WFT_STATE_SUCCESS); 34 | 35 | fprintf(stderr, "%d + %d = %d\n", input->x, input->y, output->res); 36 | } 37 | 38 | int main() 39 | { 40 | using AddFactory = WFThreadTaskFactory; 41 | AddTask *task = AddFactory::create_thread_task("add_task", 42 | add_routine, 43 | callback); 44 | AddInput *input = task->get_input(); 45 | 46 | input->x = 1; 47 | input->y = 2; 48 | 49 | task->start(); 50 | 51 | getchar(); 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /demos/24_thrd_task/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(24_thrd_task_01 24_thrd_task_01.cc) 2 | target_link_libraries(24_thrd_task_01 workflow spdlog::spdlog) 3 | 4 | -------------------------------------------------------------------------------- /demos/25_msgque/25_msgque.cc: -------------------------------------------------------------------------------- 1 | #include "msgqueue.h" 2 | #include 3 | #include 4 | 5 | // https://github.com/sogou/workflow/issues/353 6 | 7 | 8 | // wrong way: 9 | // int main(int argc, char* argv[]) { 10 | // msgqueue_t* tmp_mq = msgqueue_create(10, 0); 11 | // char str[] = "hello"; 12 | 13 | // msgqueue_put(str, tmp_mq); 14 | // char* p = msgqueue_get(tmp_mq); 15 | // printf("%s\n", p); 16 | // printf("%c\n", *p++); 17 | 18 | // return 0; 19 | // } 20 | 21 | 22 | // because : 23 | // The second argument of msgqueue_create() is the offset from the head each message, 24 | // where users have to reserve bytes of a pointer size for internal linking. 25 | // This will reduce the allocating and freeing of memory. 26 | 27 | int main() 28 | { 29 | msgqueue_t *mq = msgqueue_create(10, -static_cast(sizeof (void *))); 30 | char str[sizeof (void *) + 6]; 31 | char *p = str + sizeof (void *); 32 | strcpy(p, "hello"); 33 | msgqueue_put(p, mq); 34 | p = static_cast(msgqueue_get(mq)); 35 | printf("%s\n", p); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /demos/25_msgque/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(25_msgque_01 msgqueue.c 25_msgque.cc) 2 | -------------------------------------------------------------------------------- /demos/25_msgque/msgqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _MSGQUEUE_H_ 20 | #define _MSGQUEUE_H_ 21 | 22 | #include 23 | 24 | typedef struct __msgqueue msgqueue_t; 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* A simple implementation of message queue. The max pending messages may 32 | * reach two times 'maxlen' when the queue is in blocking mode, and infinite 33 | * in nonblocking mode. 'linkoff' is the offset from the head of each message, 34 | * where spaces of one pointer size should be available for internal usage. 35 | * 'linkoff' can be positive or negative or zero. */ 36 | 37 | msgqueue_t *msgqueue_create(size_t maxlen, int linkoff); 38 | void msgqueue_put(void *msg, msgqueue_t *queue); 39 | void *msgqueue_get(msgqueue_t *queue); 40 | void msgqueue_set_nonblock(msgqueue_t *queue); 41 | void msgqueue_set_block(msgqueue_t *queue); 42 | void msgqueue_destroy(msgqueue_t *queue); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /demos/26_resource_pool/26_issue_559_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "json.hpp" 6 | 7 | using namespace protocol; 8 | using json = nlohmann::json; 9 | 10 | // 观察结果可看出是顺序发送,并且顺序收到的 11 | 12 | static WFFacilities::WaitGroup wait_group(1); 13 | 14 | void sig_handler(int signo) 15 | { 16 | wait_group.done(); 17 | } 18 | 19 | void http_callback(WFHttpTask *task) 20 | { 21 | HttpResponse *resp = task->get_resp(); 22 | const void *body; 23 | size_t len; 24 | resp->get_parsed_body(&body, &len); 25 | fprintf(stderr, "%s", static_cast(body)); 26 | } 27 | 28 | WFHttpTask *create_post_task(const std::string &url, int uid, int cnt) 29 | { 30 | auto post_task = WFTaskFactory::create_http_task(url, 4, 2, http_callback); 31 | post_task->get_req()->set_method("POST"); 32 | json js; 33 | js["uid"] = uid; 34 | js["cnt"] = cnt; 35 | post_task->get_req()->append_output_body(js.dump()); 36 | return post_task; 37 | } 38 | 39 | int main() 40 | { 41 | signal(SIGINT, sig_handler); 42 | std::string url = "http://127.0.0.1:8888/"; 43 | const int uid = 888; // 模拟单个uid顺序 44 | int cnt = 0; 45 | WFHttpTask *first_task = create_post_task(url, uid, cnt++); 46 | 47 | SeriesWork *series = Workflow::create_series_work(first_task, 48 | [](const SeriesWork *series) 49 | { 50 | fprintf(stderr, "All tasks have done"); 51 | }); 52 | 53 | for (int i = 0; i < 20; i++) 54 | { 55 | series->push_back(create_post_task(url, uid, cnt++)); 56 | } 57 | 58 | series->start(); 59 | wait_group.wait(); 60 | } -------------------------------------------------------------------------------- /demos/26_resource_pool/26_resource_pool_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | int res_concurrency = 3; 8 | int task_concurrency = 10; 9 | const char *words[3] = {"http", "mysql", "redis"}; 10 | WFResourcePool res_pool((void * const*)words, res_concurrency); 11 | 12 | WFFacilities::WaitGroup wg(task_concurrency); 13 | 14 | for (int i = 0; i < task_concurrency; i++) 15 | { 16 | auto *user_task = WFTaskFactory::create_timer_task(0, 17 | [&wg, &res_pool](WFTimerTask *task) { 18 | uint64_t id = (uint64_t)series_of(task)->get_context(); 19 | printf("task-%lu get [%s]\n", id, (char *)task->user_data); 20 | res_pool.post(task->user_data); 21 | wg.done(); 22 | }); 23 | 24 | auto *cond = res_pool.get(user_task, &user_task->user_data); // 用user_data来保存res是一种实用方法。 25 | 26 | SeriesWork *series = Workflow::create_series_work(cond, nullptr); 27 | series->set_context(reinterpret_cast(i)); 28 | series->start(); 29 | } 30 | 31 | wg.wait(); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /demos/26_resource_pool/26_resource_pool_02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace protocol; 9 | 10 | static WFFacilities::WaitGroup wait_group(1); 11 | 12 | void sig_handler(int signo) 13 | { 14 | wait_group.done(); 15 | } 16 | 17 | std::atomic g_cnt; 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | signal(SIGINT, sig_handler); 22 | if (argc != 2) 23 | { 24 | fprintf(stderr, "USAGE: %s \n", argv[0]); 25 | exit(1); 26 | } 27 | int max_para = atoi(argv[1]); // 设置为1,那么则就变成了串行了 28 | 29 | WFResourcePool pool(max_para); 30 | std::vector urls = { 31 | "http://www.baidu.com", 32 | "http://www.bing.com", 33 | "http://www.sogou.com" 34 | }; 35 | 36 | WFFacilities::WaitGroup wait_group(3); 37 | 38 | for (auto &url : urls) 39 | { 40 | WFHttpTask *task = WFTaskFactory::create_http_task(url, 4, 2, 41 | [&pool, &wait_group, &url](WFHttpTask *task) 42 | { 43 | fprintf(stderr, "%d - url[%s]\n", g_cnt++, url.c_str()); 44 | pool.post(nullptr); 45 | wait_group.done(); 46 | }); 47 | // 新版代码中无需保存res,可以不传resbuf参数。 48 | // 多了一个这个接口 : WFConditional *get(SubTask *task); 49 | // WFConditional *cond = pool.get(task); 50 | // 我们旧版这个代码没有这个,所以随便拿个来装一下 51 | WFConditional *cond = pool.get(task, &task->user_data); 52 | cond->start(); 53 | } 54 | wait_group.wait(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /demos/26_resource_pool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(26_resource_pool_01 26_resource_pool_01.cc) 2 | target_link_libraries(26_resource_pool_01 workflow) 3 | 4 | add_executable(26_resource_pool_02 26_resource_pool_02.cc) 5 | target_link_libraries(26_resource_pool_02 workflow) 6 | 7 | add_executable(26_resource_pool_03 26_resource_pool_03.cc) 8 | target_link_libraries(26_resource_pool_03 workflow) 9 | 10 | add_executable(26_issue_559_server 26_issue_559_server.cc) 11 | target_link_libraries(26_issue_559_server workflow) 12 | 13 | add_executable(26_issue_559_client 26_issue_559_client.cc) 14 | target_link_libraries(26_issue_559_client workflow) 15 | -------------------------------------------------------------------------------- /demos/27_parse_uri/27_request_uri_split.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test01() { 4 | const char *request_uri = "/d?host=www.baidu.com"; 5 | const char *p = request_uri; 6 | 7 | printf("Request-URI: %s\n", request_uri); 8 | while (*p && *p != '?') 9 | p++; 10 | 11 | std::string path(request_uri, p - request_uri); 12 | printf("path: %s\n", path.c_str()); 13 | 14 | std::string query(p+1); 15 | printf("query: %s\n", query.c_str()); 16 | } 17 | 18 | // void test02() 19 | // { 20 | 21 | // } 22 | 23 | int main() { 24 | test01(); 25 | } -------------------------------------------------------------------------------- /demos/27_parse_uri/27_unorderd_split.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "workflow/StringUtil.h" 6 | 7 | std::unordered_map split_query(const std::string &query) 8 | { 9 | std::unordered_map res; 10 | 11 | if (query.empty()) 12 | return res; 13 | 14 | std::vector arr = StringUtil::split(query, '&'); 15 | 16 | if (arr.empty()) 17 | return res; 18 | 19 | for (const auto& ele : arr) 20 | { 21 | if (ele.empty()) 22 | continue; 23 | 24 | std::vector kv = StringUtil::split(ele, '='); 25 | size_t kv_size = kv.size(); 26 | std::string& key = kv[0]; 27 | 28 | if (key.empty() || res.count(key) > 0) 29 | continue; 30 | 31 | if (kv_size == 1) 32 | { 33 | res.emplace(std::move(key), ""); 34 | continue; 35 | } 36 | 37 | std::string& val = kv[1]; 38 | 39 | if (val.empty()) 40 | res.emplace(std::move(key), ""); 41 | else 42 | res.emplace(std::move(key), std::move(val)); 43 | } 44 | 45 | return res; 46 | } 47 | 48 | int main() 49 | { 50 | std::string query = "host=chanchan&password=123"; 51 | auto map = split_query(query); 52 | for(auto& m : map) 53 | { 54 | std::cout << m.first << " : " << m.second << std::endl; 55 | } 56 | return 0; 57 | } -------------------------------------------------------------------------------- /demos/27_parse_uri/27_uri_parser_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test01() 4 | { 5 | ParsedURI pu; 6 | // 这里一定要有完整的url 7 | URIParser::parse("http://127.0.0.1/d?host=www.baidu.com", pu); 8 | fprintf(stderr, "path : %s\n", pu.path); 9 | fprintf(stderr, "query : %s\n", pu.query); 10 | } 11 | 12 | std::string url = "http://127.0.0.1:9001/query_list/username=123&password=000"; 13 | 14 | // "http://127.0.0.1/api/v1/chanchan?host=www.baidu.com&name=chanchann" 15 | 16 | void test02() 17 | { 18 | ParsedURI pu; 19 | // 这里一定要有完整的url 20 | if(URIParser::parse(url, pu) < 0) 21 | { 22 | fprintf(stderr, "url is invalid ,return ..."); 23 | return; 24 | } 25 | // path : /api/v1/chanchan 26 | fprintf(stderr, "path : %s\n", pu.path); 27 | auto path_vec = URIParser::split_path(pu.path); 28 | // api v1 chanchan 29 | for(auto& p : path_vec) 30 | { 31 | fprintf(stderr, "%s\t", p.c_str()); 32 | } 33 | fprintf(stderr, "\n"); 34 | // query : host=www.baidu.com 35 | fprintf(stderr, "query : %s\n", pu.query); 36 | auto query_map = URIParser::split_query(pu.query); 37 | for(auto& q : query_map) 38 | { 39 | fprintf(stderr, "%s : %s\n", q.first.c_str(), q.second.c_str()); 40 | } 41 | } 42 | 43 | void test03() 44 | { 45 | std::string url = "http://www.sogou.com"; 46 | // std::string url = "http://www.sogou.com/"; 47 | ParsedURI pu; 48 | if(URIParser::parse(url, pu) < 0) 49 | { 50 | fprintf(stderr, "url is invalid ,return ..."); 51 | return; 52 | } 53 | fprintf(stderr, "path : %s\n", pu.path); 54 | } 55 | 56 | int main() { 57 | test03(); 58 | } -------------------------------------------------------------------------------- /demos/27_parse_uri/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(27_uri_parser_01 27_uri_parser_01.cc) 2 | target_link_libraries(27_uri_parser_01 workflow) 3 | 4 | add_executable(27_request_uri_split 27_request_uri_split.cc) 5 | target_link_libraries(27_request_uri_split workflow) 6 | 7 | add_executable(27_unorderd_split 27_unorderd_split.cc) 8 | target_link_libraries(27_unorderd_split workflow) 9 | -------------------------------------------------------------------------------- /demos/28_string_util/28_string_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void test_01() 5 | { 6 | auto split_list = StringUtil::split("123,24,21", ','); 7 | for(auto &s : split_list) 8 | { 9 | std::cout << s << std::endl; 10 | } 11 | } 12 | 13 | void test_02() 14 | { 15 | auto split_list = StringUtil::split("123", ','); 16 | for(auto &s : split_list) 17 | { 18 | std::cout << s << std::endl; 19 | } 20 | } 21 | 22 | int main() 23 | { 24 | // test_01(); 25 | test_02(); 26 | } -------------------------------------------------------------------------------- /demos/28_string_util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(28_string_01 28_string_01.cc) 2 | target_link_libraries(28_string_01 workflow) 3 | -------------------------------------------------------------------------------- /demos/29_upstream/29_upstream_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "util.h" 11 | 12 | static WFFacilities::WaitGroup wait_group(1); 13 | const int server_num = 3; 14 | 15 | void sig_handler(int signo) 16 | { 17 | wait_group.done(); 18 | } 19 | 20 | void server_process(WFHttpTask *task, std::string& name) 21 | { 22 | auto *resp = task->get_resp(); 23 | fprintf(stderr, "name : %s\n", name.c_str()); 24 | resp->append_output_body(name); 25 | } 26 | 27 | int main() 28 | { 29 | signal(SIGINT, sig_handler); 30 | std::vector > server_list(server_num); 31 | unsigned int port = 8000; 32 | for (int i = 0; i < server_num; i++) 33 | { 34 | server_list[i] = 35 | util::make_unique(std::bind(&server_process, 36 | std::placeholders::_1, 37 | "server-" + std::to_string(i))); 38 | 39 | if (server_list[i]->start("127.0.0.1", port++) != 0) 40 | { 41 | fprintf(stderr, "http server start failed"); 42 | wait_group.done(); 43 | break; 44 | } 45 | } 46 | 47 | wait_group.wait(); 48 | for(auto& server : server_list) { 49 | server->stop(); 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /demos/29_upstream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(29_upstream_server 29_upstream_server.cc) 2 | target_link_libraries(29_upstream_server workflow) 3 | 4 | add_executable(29_upstream_random 29_upstream_random.cc) 5 | target_link_libraries(29_upstream_random workflow) 6 | 7 | add_executable(29_upstream_weighted 29_upstream_weighted.cc) 8 | target_link_libraries(29_upstream_weighted workflow) 9 | 10 | add_executable(29_upstream_hash 29_upstream_hash.cc) 11 | target_link_libraries(29_upstream_hash workflow) 12 | 13 | add_executable(29_upstream_hash_define 29_upstream_hash_define.cc) 14 | target_link_libraries(29_upstream_hash_define workflow) 15 | 16 | add_executable(29_upstream_manual 29_upstream_manual.cc) 17 | target_link_libraries(29_upstream_manual workflow) 18 | -------------------------------------------------------------------------------- /demos/29_upstream/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/demos/29_upstream/readme.md -------------------------------------------------------------------------------- /demos/30_kernel_comm/30_test_server.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | static WFFacilities::WaitGroup wait_group(1); 7 | 8 | void sig_handler(int signo) 9 | { 10 | wait_group.done(); 11 | } 12 | 13 | int main() 14 | { 15 | signal(SIGINT, sig_handler); 16 | WFHttpServer server([](WFHttpTask *task) { 17 | task->get_resp()->append_output_body("server test"); 18 | return; 19 | }); 20 | 21 | if (server.start(8888) == 0) { 22 | wait_group.wait(); 23 | server.stop(); 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /demos/30_kernel_comm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(30_kernel_comm_01 30_kernel_comm_01.cc) 2 | target_link_libraries(30_kernel_comm_01 workflow) 3 | 4 | add_executable(30_test_server 30_test_server.cc) 5 | target_link_libraries(30_test_server workflow) 6 | -------------------------------------------------------------------------------- /demos/31_mysql/31_02_conn.cc: -------------------------------------------------------------------------------- 1 | #include "workflow/WFMySQLConnection.h" 2 | #include "workflow/WFOperator.h" 3 | 4 | int id = 0; 5 | 6 | void task_callback(WFMySQLTask *task) 7 | { 8 | fprintf(stderr, "t%d\n", ++id); 9 | } 10 | 11 | int main() 12 | { 13 | WFMySQLConnection conn(1); 14 | conn.init("mysql://root@127.0.0.1/wfrest_test"); 15 | 16 | // test transaction 17 | const char *query = "BEGIN;"; 18 | WFMySQLTask *t1 = conn.create_query_task(query, task_callback); 19 | query = "SELECT * FROM check_tiny FOR UPDATE;"; 20 | WFMySQLTask *t2 = conn.create_query_task(query, task_callback); 21 | query = "INSERT INTO check_tiny VALUES (8);"; 22 | WFMySQLTask *t3 = conn.create_query_task(query, task_callback); 23 | query = "COMMIT;"; 24 | WFMySQLTask *t4 = conn.create_query_task(query, task_callback); 25 | WFMySQLTask *t5 = conn.create_disconnect_task(task_callback); 26 | 27 | ((*t1) > t2 > t3 > t4 > t5).start(); 28 | getchar(); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /demos/31_mysql/31_mysql_cli.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "workflow/Workflow.h" 9 | #include "workflow/WFTaskFactory.h" 10 | #include "workflow/MySQLResult.h" 11 | #include "workflow/WFFacilities.h" 12 | 13 | static const int RETRY_MAX = 0; 14 | volatile bool stop_flag; 15 | 16 | static void sighandler(int signo) 17 | { 18 | stop_flag = true; 19 | } 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | if (argc != 2) 24 | { 25 | fprintf(stderr, "USAGE: %s \n" 26 | " url format: mysql://root:password@host:port/dbname?character_set=charset\n" 27 | " example: mysql://root@test.mysql.com/test\n", 28 | argv[0]); 29 | return 0; 30 | } 31 | 32 | signal(SIGINT, sighandler); 33 | // SIGTERM是杀或的killall命令发送到进程默认的信号 34 | signal(SIGTERM, sighandler); 35 | 36 | std::string url = argv[1]; 37 | if (strncasecmp(argv[1], "mysql://", 8) != 0 && 38 | strncasecmp(argv[1], "mysqls://", 9) != 0) 39 | { 40 | url = "mysql://" + url; 41 | } 42 | std::string a; 43 | const char *query = "show databases"; 44 | stop_flag = false; 45 | 46 | WFMySQLTask *task = WFTaskFactory::create_mysql_task(url, RETRY_MAX, mysql_callback); 47 | task->get_req()->set_query(query); 48 | 49 | WFFacilities::WaitGroup wait_group(1); 50 | SeriesWork *series = Workflow::create_series_work(task, 51 | [&wait_group](const SeriesWork *series) { 52 | wait_group.done(); 53 | }); 54 | 55 | series->set_context(&url); 56 | series->start(); 57 | 58 | wait_group.wait(); 59 | return 0; 60 | } -------------------------------------------------------------------------------- /demos/31_mysql/31_mysql_intro_demo.cc: -------------------------------------------------------------------------------- 1 | #include "workflow/Workflow.h" 2 | #include "workflow/WFTaskFactory.h" 3 | #include "workflow/MySQLResult.h" 4 | 5 | using namespace protocol; 6 | 7 | int main() 8 | { 9 | std::string url = "mysql://root:123@localhost"; 10 | WFMySQLTask *task = WFTaskFactory::create_mysql_task(url, 0, [](WFMySQLTask *task) 11 | { 12 | MySQLResponse *resp = task->get_resp(); 13 | MySQLResultCursor cursor(resp); 14 | std::vector arr; 15 | while (cursor.fetch_row(arr)) 16 | { 17 | fprintf(stderr, "[%s]\n", arr[0].as_string().c_str()); 18 | } 19 | }); 20 | task->get_req()->set_query("SHOW DATABASES"); 21 | task->start(); 22 | getchar(); 23 | } -------------------------------------------------------------------------------- /demos/31_mysql/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(31_01_show_db 31_01_show_db.cc) 2 | target_link_libraries(31_01_show_db workflow) 3 | 4 | add_executable(31_02_conn 31_02_conn.cc) 5 | target_link_libraries(31_02_conn workflow) 6 | 7 | add_executable(31_mysql_intro_demo 31_mysql_intro_demo.cc) 8 | target_link_libraries(31_mysql_intro_demo workflow) 9 | -------------------------------------------------------------------------------- /demos/33_header/33_header_pair.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void process(WFHttpTask *server_task) 11 | { 12 | protocol::HttpRequest *req = server_task->get_req(); 13 | protocol::HttpResponse *resp = server_task->get_resp(); 14 | 15 | // {'set': '234', 'add': '123, 234' 16 | // set会覆盖 17 | resp->set_header_pair("set", "123"); 18 | resp->set_header_pair("set", "234"); 19 | 20 | // add是在后面加上 21 | resp->add_header_pair("add", "123"); 22 | resp->add_header_pair("add", "234"); 23 | 24 | resp->append_output_body_nocopy("test", 4); 25 | } 26 | 27 | int main() 28 | { 29 | WFHttpServer server(process); 30 | 31 | if (server.start(8888) == 0) 32 | { 33 | getchar(); 34 | server.stop(); 35 | } 36 | else 37 | { 38 | fprintf(stderr, "Cannot start server"); 39 | exit(1); 40 | } 41 | 42 | return 0; 43 | } -------------------------------------------------------------------------------- /demos/33_header/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(33_header_pair 33_header_pair.cc) 2 | target_link_libraries(33_header_pair workflow) 3 | -------------------------------------------------------------------------------- /demos/33_header/test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | if __name__ == "__main__": 4 | url = "http://127.0.0.1:8888/" 5 | 6 | resp = requests.get(url) 7 | 8 | print(resp.headers) 9 | print(resp.content) -------------------------------------------------------------------------------- /demos/34_https/34_https_test.cc: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/24611640/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate 2 | // https://zhuanlan.zhihu.com/p/86926335 3 | // https://blog.csdn.net/weiyuanke/article/details/87256937 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void process(WFHttpTask *server_task) 14 | { 15 | protocol::HttpRequest *req = server_task->get_req(); 16 | protocol::HttpResponse *resp = server_task->get_resp(); 17 | fprintf(stderr, "uri : %s\n", req->get_request_uri()); 18 | resp->append_output_body_nocopy("test\n", 5); 19 | } 20 | 21 | int main(int argc, char **argv) 22 | { 23 | if (argc != 3) 24 | { 25 | fprintf(stderr, "%s [cert file] [key file]\n", 26 | argv[0]); 27 | exit(1); 28 | } 29 | 30 | WFHttpServer server(process); 31 | 32 | if (server.start(8888, argv[1], argv[2]) == 0) 33 | { 34 | getchar(); 35 | server.stop(); 36 | } 37 | else 38 | { 39 | fprintf(stderr, "Cannot start server"); 40 | exit(1); 41 | } 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /demos/34_https/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(34_https_test 34_https_test.cc) 2 | target_link_libraries(34_https_test workflow) 3 | -------------------------------------------------------------------------------- /demos/34_https/gen.sh: -------------------------------------------------------------------------------- 1 | openssl genrsa -out server.key 2048 2 | openssl req -new -x509 -key server.key -out server.crt -days 3650 3 | -------------------------------------------------------------------------------- /demos/34_https/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDazCCAlOgAwIBAgIUb7rYbZ/o4hMB+7U43togEgeMho0wDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMTEyMjExMzI3MjRaFw0zMTEy 5 | MTkxMzI3MjRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQDMj/QhMeB4GVTXWKKLYOvscFihwCaEA55fMiN4kWYC 8 | FFxP+Fg0kIrtl/3w0pLbyamTLFRXR+Bg9QYq9VB0iSsDF3G06vc0ugOBto72/hSW 9 | RBdEml4RXXKoOgqTuGByzU8NH/pZCLX/S5EFbyv+gGpPE1doea0DVy1Mqh984rwy 10 | o+PqNfcll8pb8pMLQTjbfkkvBKCTTUFZUdHB/pY2qjr7DvMpCjRyH9LNHhlYZluY 11 | /JMy2/gdcCV7xHmCrkig8o9uOkOh7xlNmsWtbnpFSlnlxbCETv2ZftMSnfc5teZe 12 | ntEIKGAu6P/66S3MlIwiIMOArW747GHYpN3KjntUDMVxAgMBAAGjUzBRMB0GA1Ud 13 | DgQWBBQdr5nvUerpCO7LoEGh4LLujq0MMjAfBgNVHSMEGDAWgBQdr5nvUerpCO7L 14 | oEGh4LLujq0MMjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB7 15 | WYWSD7xu17T1ZTi9nP62ZH8mfnF1Etoj7xgJP5E8IhKnuccWf+amjLRB0I5XDlj+ 16 | t7c5N7nqteOhfnh8+liJ9ssMEYp6SkQUZhS9yVDLlWoXzpbuSz78BGJp7i8Qff4y 17 | pkfyd3pAMBYPrhQHCTY01n9qXPbbDqv+p4/PkFYKPW8hkDsSfZwlvtyloSGrQNyC 18 | 5t3CCFluyHw6KgVk5UoOM/ySRTKxX1KPfmyrIKONahkgduk3YLceifPv7ZIdelZO 19 | ddd2Q09Mr09rdbzDADOrMxvcN7qhPWnPNEsHw1A5MikWlk781bRE1nA4etpUUXJZ 20 | E/rJj64NPC8wV8BgvcMr 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /demos/34_https/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAzI/0ITHgeBlU11iii2Dr7HBYocAmhAOeXzIjeJFmAhRcT/hY 3 | NJCK7Zf98NKS28mpkyxUV0fgYPUGKvVQdIkrAxdxtOr3NLoDgbaO9v4UlkQXRJpe 4 | EV1yqDoKk7hgcs1PDR/6WQi1/0uRBW8r/oBqTxNXaHmtA1ctTKoffOK8MqPj6jX3 5 | JZfKW/KTC0E4235JLwSgk01BWVHRwf6WNqo6+w7zKQo0ch/SzR4ZWGZbmPyTMtv4 6 | HXAle8R5gq5IoPKPbjpDoe8ZTZrFrW56RUpZ5cWwhE79mX7TEp33ObXmXp7RCChg 7 | Luj/+uktzJSMIiDDgK1u+Oxh2KTdyo57VAzFcQIDAQABAoIBAFEqvV9+fuaohnV8 8 | AeLz7ii+2ywzJhUzql9zcYehiaxBj+9bRwR0ZeuoZ2Zq50K2Xca7zCtlpa5TCsN4 9 | 2xeiZaKwZrm2kagmNsX9PfTbFCgblG/wIGsbfScrAI9klUB4HmnCyn8RacWGomBZ 10 | oEc3hPcjYYde4Dt3F85Xom7XOH2Ou7rUh5jKppSc94cX/rMWJNmIo5TufHl36Q1k 11 | HakCD8vLrJFc/bJOCIKcdP0vsDE5mvdcEu1pZXCDOuQ0/T6EinPgL0kgenxqBBc8 12 | +nIrHyDw+MTIjn3fOM8TaYrDUFJygrKFrZ4DbWzn/HKgvouo/qqmGkgJJkBByp5M 13 | TR3TqMECgYEA+weiwSF/a0Rwui8jz2J45yIw62dMg6aOj19v0n45fYbb0lLf8D8M 14 | CPDObUb+KNTESfZTxddpLESNZ50QPO9kAxGD8/Cv4iB4wKdFO1KHoJ4Py2yxj4fJ 15 | ifKDxf48hOI/2kqanuzbzC44hYyUcS9Q89VbC6rAVrwX5ecT2EDs/JUCgYEA0JzL 16 | LvRIQw/BDF3LDcTlLAahQLbKvTnn+YWX1LiPrwXn1TgzziZILHVJkojV5LWNqCss 17 | 7worLHe//rmh+CCWN7G0WcKnkpCtS+64aOUUsneN8r1Eex5zLpnbz4NAuVyGcwJO 18 | FBL74Zz9HfdV0iIwTh4GJFFoHNFqe9hiiwhn0m0CgYEAppAZeOZeInGmDpPKwgdH 19 | y61PIlNHXK8+NnmPu+5O/TBnWTXuKv3aYXBOuAl8COGsYJsWWNamjV3rKY34wUXi 20 | aXrMwCa6vWLoXIRglo0bOwLF3id/5Ymmu2Zz8wLPayioT5Ji6AKnkOI2VL7DnBpW 21 | L4QoxiQFPUfO35gk/b+Ov8UCgYEAwNY/h/7uEXetpyXIfsjkY2cZhn2yOWsewWw5 22 | pryYrVyTKmkSklyW2OnugZMVzZ35/Vsz5R+MO0XS579nNrvAwGj3YwXp6zTrzMY2 23 | F1izYinbwGgutnS2WnyFUXRtzyr1abjWvf2ycqKw5BNvdJh/+KYOXWIXEJSQjzy+ 24 | EvFJL50CgYBgQ1ntXhaoG/HUs/2Czhb0Js6ptBhXcG1iumq8KPMWhUt98sySQpOG 25 | Z2YLZ/aLNeTxS4PyMUHNuCeMl/Vd2AufyWQoWDdK73dYlwqVD/Gg9eRF0k7i4cEk 26 | RmIyJ8cxllB1+lRdOVnnowWJ1i4oj18aZjeywLXVn8RazNj2+oPW7A== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /demos/35_dismiss/35_dismiss_test.cc: -------------------------------------------------------------------------------- 1 | // 测试SeriesWork的dismiss 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static WFFacilities::WaitGroup wait_group(1); 8 | 9 | void sig_handler(int signo) 10 | { 11 | wait_group.done(); 12 | } 13 | 14 | int main() 15 | { 16 | signal(SIGINT, sig_handler); 17 | WFHttpServer server([](WFHttpTask *task) { 18 | int cnt = 1; 19 | WFGoTask *go_task1 = WFTaskFactory::create_go_task("go", [](int n) { fprintf(stderr, "%d\n", n); }, cnt++); 20 | **task << go_task1; 21 | WFGoTask *go_task2 = WFTaskFactory::create_go_task("go", [](int n) { fprintf(stderr, "%d\n", n); }, cnt++); 22 | **task << go_task2; 23 | // series_of(task)->cancel(); 24 | // series_of(task)->dismiss(); 25 | }); 26 | 27 | if (server.start(8888) == 0) { 28 | wait_group.wait(); 29 | server.stop(); 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /demos/35_dismiss/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(35_dismiss_test 35_dismiss_test.cc) 2 | target_link_libraries(35_dismiss_test workflow) 3 | -------------------------------------------------------------------------------- /demos/36_task/36_parallel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | ParallelWork *pwork = Workflow::create_parallel_work(nullptr); 8 | for(int i = 0; i < 3; i++) 9 | { 10 | WFTimerTask *task = WFTaskFactory::create_timer_task(3000 * 1000, 11 | [](WFTimerTask *timer) 12 | { 13 | fprintf(stderr, "timer end\n"); 14 | }); 15 | SeriesWork *series = Workflow::create_series_work(task, nullptr); 16 | pwork->add_series(series); 17 | } 18 | pwork->start(); 19 | getchar(); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /demos/36_task/36_series.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | WFTimerTask *task = WFTaskFactory::create_timer_task(3000 * 1000, 8 | [](WFTimerTask *timer) 9 | { 10 | fprintf(stderr, "timer end\n"); 11 | }); 12 | 13 | task->start(); 14 | getchar(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /demos/36_task/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(36_series 36_series.cc) 2 | target_link_libraries(36_series workflow) 3 | 4 | add_executable(36_parallel 36_parallel.cc) 5 | target_link_libraries(36_parallel workflow) 6 | 7 | -------------------------------------------------------------------------------- /demos/37_rb_tree/Makefile: -------------------------------------------------------------------------------- 1 | all:37_rb_tree_01 2 | 3 | CFLAGS=-g -O0 -Wall 4 | 5 | 37_rb_tree_01:37_rb_tree_01.o rbtree.o 6 | 7 | rbtree.o:rbtree.h rbtree.c 8 | 9 | 37_rb_tree_01.o:37_rb_tree_01.c 10 | 11 | .PHONY:clean 12 | 13 | clean: 14 | rm *.o 37_rb_tree_01 -------------------------------------------------------------------------------- /demos/38_json_parser/test.json: -------------------------------------------------------------------------------- 1 | [1,2,[3,4,5, [6,7]],null] 2 | -------------------------------------------------------------------------------- /demos/38_json_parser/test_speed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "json_parser.h" 4 | 5 | #define BUFSIZE (64 * 1024 * 1024) 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | static char buf[BUFSIZE]; 10 | size_t n; 11 | 12 | if (argc != 2) 13 | { 14 | fprintf(stderr, "USAGE: %s \n", argv[0]); 15 | exit(1); 16 | } 17 | 18 | n = fread(buf, 1, BUFSIZE, stdin); 19 | if (n > 0) 20 | { 21 | if (n == BUFSIZE) 22 | { 23 | fprintf(stderr, "File too large.\n"); 24 | exit(1); 25 | } 26 | 27 | buf[n] = '\0'; 28 | } 29 | else 30 | { 31 | perror("fread"); 32 | exit(1); 33 | } 34 | 35 | int rep = atoi(argv[1]); 36 | int i; 37 | 38 | for (i = 0; i < rep; i++) 39 | { 40 | json_value_t *val = json_value_parse(buf); 41 | if (val) 42 | { 43 | json_value_destroy(val); 44 | } 45 | else 46 | { 47 | fprintf(stderr, "Invalid JSON document.\n"); 48 | exit(1); 49 | } 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /demos/3rd/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace util 8 | { 9 | template 10 | std::unique_ptr make_unique(Args&&... args) { 11 | return std::unique_ptr(new T(std::forward(args)...)); 12 | } 13 | 14 | static const int INET_ADDR_LEN = 128; 15 | 16 | static inline std::string ip_bin_to_str(void* sa_sin_addr, bool ipv4 = true) 17 | { 18 | struct sockaddr_in sa; 19 | char str[INET_ADDR_LEN]; 20 | if(ipv4) 21 | inet_ntop(AF_INET, sa_sin_addr, str, INET_ADDR_LEN); 22 | else 23 | inet_ntop(AF_INET6, sa_sin_addr, str, INET_ADDR_LEN); 24 | return str; 25 | } 26 | 27 | 28 | } // namespace util 29 | -------------------------------------------------------------------------------- /demos/other/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(01_other 01_other.cc) 2 | target_link_libraries(01_other workflow) 3 | -------------------------------------------------------------------------------- /demos/readme.md: -------------------------------------------------------------------------------- 1 | ## 依赖 2 | 3 | workflow 4 | 5 | spdlog 6 | 7 | 两个都是编译丝滑型,问题不大 8 | 9 | -------------------------------------------------------------------------------- /other/01_transfer_encoding.md: -------------------------------------------------------------------------------- 1 | ## transfer encoding 2 | 3 | 1. Transfer-Encoding vs Content-Encoding 4 | 5 | 改变报文格式(可能变大) vs 压缩编码优化传输 6 | 7 | 2. When use Content-Encoding 8 | 9 | 例如用 gzip 压缩文本文件,能大幅减小体积。内容编码通常是选择性的,例如 jpg / png 这类文件一般不开启,因为图片格式已经是高度压缩过的 10 | 11 | 3. Why use Transfer-Encoding 12 | 13 | With chunked transfer encoding (CTE), the encoder sends data to the player in a series of chunks instead of waiting until the complete segment is availabl 14 | 15 | 4. Persistent Connection 16 | 17 | HTTP/1.0 的持久连接机制是后来才引入的,通过 Connection: keep-alive 这个头部来实现,服务端和客户端都可以使用它告诉对方在发送完数据之后不需要断开 TCP 连接,以备后用。HTTP/1.1 则规定所有连接都必须是持久的,除非显式地在头部加上 Connection: close 18 | 19 | Why mention Persistent Connection here ? 20 | 21 | So we need Content-Length. 22 | 23 | 5. Why we need Content-Length. 24 | 25 | 6. If Content-Length != message length 26 | 27 | 7. Content-Length leads to what problem, how to solve it? 28 | 29 | 8. Transfer-Encoding: chunked 30 | 31 | The transmission ends when a zero-length chunk is received. 32 | 33 | ``` 34 | HTTP/1.1 200 OK 35 | Content-Type: text/plain 36 | Transfer-Encoding: chunked 37 | 5\r\n 38 | Media\r\n 39 | 8\r\n 40 | Services\r\n 41 | 4\r\n 42 | Live\r\n 43 | 0\r\n 44 | \r\n 45 | ``` 46 | 47 | ## ref 48 | 49 | https://imququ.com/post/transfer-encoding-header-in-http.html 50 | 51 | https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html 52 | 53 | https://learn.akamai.com/en-us/webhelp/media-services-live/media-services-live-encoder-compatibility-testing-and-qualification-guide-v4.0/GUID-A7D10A31-F4BC-49DD-92B2-8A5BA409BAFE.html 54 | 55 | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding -------------------------------------------------------------------------------- /other/Json/test01.cc: -------------------------------------------------------------------------------- 1 | #include "json.hpp" 2 | #include 3 | using Json = nlohmann::json; 4 | 5 | struct table 6 | { 7 | int row_num; 8 | int col_num; 9 | 10 | }; 11 | 12 | int main() 13 | { 14 | Json json1; 15 | Json json2 = {1 , 2, 3}; 16 | json1["1"] = json2; 17 | json2.push_back("4"); 18 | json1["2"] = json2; 19 | std::cout << json1.dump() << std::endl; 20 | 21 | 22 | } -------------------------------------------------------------------------------- /other/base_to_derived/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Base { 4 | public: 5 | Base() : b(new int) {}; 6 | ~Base() { delete b; }; 7 | Base(Base&& other) 8 | : a(other.a) 9 | { b = other.b; other.b = nullptr; } 10 | 11 | Base &operator=(Base &&other) 12 | { a = other.a; b = other.b; other.b = nullptr; return *this; } 13 | 14 | int a = 0; 15 | int *b; 16 | }; 17 | 18 | class Derived : public Base 19 | { 20 | public: 21 | Derived() : c(new int) {}; 22 | ~Derived() { delete c; }; 23 | Derived(Derived&& other) 24 | { c = other.c; other.c = nullptr; } 25 | 26 | Derived &operator=(Derived &&other) 27 | { c = other.c; other.c = nullptr; return *this; } 28 | 29 | int *c; 30 | }; 31 | 32 | int main() 33 | { 34 | Base *base = new Base(); 35 | // Derived *derived = std::move(static_cast(base)); 36 | Derived *derived = new Derived; 37 | *derived = std::move(*static_cast(base)); 38 | derived->c; 39 | } -------------------------------------------------------------------------------- /other/c_thread/readme.md: -------------------------------------------------------------------------------- 1 | ## pthread_key_t和pthread_key_create() 2 | 3 | https://www.jianshu.com/p/d52c1ebf808a 4 | 5 | 在多线程程序中,所有线程共享程序中的变量 6 | 7 | 现在有一全局变量,所有线程都可以使用它,改变它的值。 8 | 9 | 而如果每个线程希望能单独拥有它,那么就需要使用线程存储了。 10 | 11 | 表面上看起来这是一个全局变量,所有线程都可以使用它,而它的值在每一个线程中又是单独存储的。这就是线程存储的意义 12 | 13 | -------------------------------------------------------------------------------- /other/callback/func_ptr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test() 4 | {} 5 | typeded void(*next)() {} 6 | 7 | template 8 | std::function cast(void* f) 9 | { 10 | return static_cast(f); 11 | } 12 | 13 | int main() 14 | { 15 | std::function f = cast(&test); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /other/callback/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Handler = std::function; 5 | 6 | struct A 7 | { 8 | Handler handler; 9 | }; 10 | 11 | 12 | int main() 13 | { 14 | A a; 15 | if(a.handler) std::cout << "1" << std::endl; 16 | else std::cout << "2" << std::endl; 17 | } -------------------------------------------------------------------------------- /other/callback/test2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Handler = std::function; 5 | using SeriesHandler = std::function; 6 | 7 | struct A 8 | { 9 | Handler handler; 10 | SeriesHandler series_handler; 11 | }; 12 | 13 | void foo_a(int i) 14 | { 15 | std::cout << i << std::endl; 16 | } 17 | 18 | void foo_b(int i, int j) 19 | { 20 | std::cout << i << " " << j << std::endl; 21 | } 22 | 23 | int main() 24 | { 25 | A a; 26 | a.handler = foo_a; 27 | a.handler(1); 28 | 29 | A a1; 30 | a1.series_handler = foo_b; 31 | if(foo_b) 32 | { 33 | foo_b(1, 2); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /other/callback_param/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // stack overflow but can't compile 4 | struct Call 5 | { 6 | template 7 | explicit Call(F f) : zero_(f), one_(std::move(f)) {} 8 | 9 | void operator()() { zero_(); } 10 | void operator()(int i) { one_(i); } 11 | 12 | std::function zero_; 13 | std::function one_; 14 | }; 15 | 16 | int main() 17 | { 18 | Call c1([]() { fprintf(stderr, "no param\n"); }); 19 | // c1(); 20 | 21 | // Call c2([](int i) { fprintf(stderr, "%d\n", i); }); 22 | // c2(1); 23 | } -------------------------------------------------------------------------------- /other/callback_param/test_01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Handler = std::function; 5 | using SeriesHandler = std::function; 6 | 7 | class Foo 8 | { 9 | public: 10 | void handle(const Handler &handler) 11 | { 12 | handler_ = [&] (int i, int j, int k) { handler(i, j); }; 13 | } 14 | 15 | // void handle(const Handler &handler, int compute_id) 16 | // { 17 | // handler_ = [&] (int i, int j, int k) { 18 | // WFGoTask *go_task = WFTaskFactory::create_go_task( 19 | // "wfrest" + std::to_string(compute_id), 20 | // handler, 21 | // i, j); 22 | // return go_task; 23 | // }; 24 | // } 25 | 26 | void handle(const SeriesHandler &handler) 27 | { 28 | handler_ = handler; 29 | } 30 | 31 | void operator()(int i, int j, int k) { handler_(i, j, k); } 32 | private: 33 | SeriesHandler handler_; 34 | }; 35 | 36 | 37 | int main() 38 | { 39 | Foo foo1; 40 | foo1.handle([](int i, int j) { std::cout << "i : " << i << " j : " << j << std::endl; }); 41 | foo1(1, 2, 3); 42 | 43 | Foo foo2; 44 | foo2.handle([](int i, int j, int k) { std::cout << "i : " << i << " j : " << j << " k : " << k << std::endl; }); 45 | foo2(1, 2, 3); 46 | } -------------------------------------------------------------------------------- /other/cmake/find_cmake.md: -------------------------------------------------------------------------------- 1 | ## Find.cmake模块 2 | 3 | ``` 4 | # 在指定目录下寻找头文件和动态库文件的位置,可以指定多个目标路径 5 | find_path(ADD_INCLUDE_DIR libadd.h /usr/include/ /usr/local/include ${CMAKE_SOURCE_DIR}/ModuleMode) 6 | find_library(ADD_LIBRARY NAMES add PATHS /usr/lib/add /usr/local/lib/add ${CMAKE_SOURCE_DIR}/ModuleMode) 7 | 8 | if (ADD_INCLUDE_DIR AND ADD_LIBRARY) 9 | set(ADD_FOUND TRUE) 10 | endif (ADD_INCLUDE_DIR AND ADD_LIBRARY) 11 | ``` -------------------------------------------------------------------------------- /other/cmake/install.md: -------------------------------------------------------------------------------- 1 | ## install 2 | 3 | 将项目生成的库文件、头文件、可执行文件或相关文件等安装到指定位置(系统目录,或发行包目录) 4 | 5 | cmake中,这主要是通过install方法在CMakeLists.txt中配置,make install命令安装相关文件来实现的。 6 | 7 | ``` 8 | install(TARGETS MyLib 9 | EXPORT MyLibTargets 10 | LIBRARY DESTINATION lib # 动态库安装路径,可选 11 | ARCHIVE DESTINATION lib # 静态库安装路径,可选 12 | RUNTIME DESTINATION bin # 可执行文件安装路径,可选 13 | PUBLIC_HEADER DESTINATION include # 头文件安装路径,可选 14 | ) 15 | ``` 16 | 17 | `DESTINATION` 路径可以set,根目录默认为CMAKE_INSTALL_PREFIX, 默认值为 `/usr/local` 18 | 19 | 安装完成后,希望可以通过find_package方法进行引用,我们拿workflow的cmake做例子来看看 20 | 21 | ## for find_package 22 | 23 | 1. 需要生成一个XXXConfigVersion.cmake, 声明版本信息 24 | 25 | ```cpp 26 | # 写入库的版本信息 27 | include(CMakePackageConfigHelpers) 28 | write_basic_package_version_file( 29 | XXXConfigVersion.cmake 30 | VERSION ${PACKAGE_VERSION} 31 | COMPATIBILITY AnyNewerVersion # 表示该函数库向下兼 32 | ) 33 | ``` 34 | 35 | 2. 将前面EXPORT MyLibTargets的信息写入到MyLibTargets.cmake文件中 36 | 37 | ``` 38 | install(EXPORT MyLibTargets 39 | FILE MyLibTargets.cmake 40 | NAMESPACE XXX:: 41 | DESTINATION lib/cmake/MyLib 42 | ``` 43 | ) 44 | 45 | 46 | 47 | ## ref 48 | 49 | https://zhuanlan.zhihu.com/p/102955723 50 | 51 | https://github.com/BrightXiaoHan/CMakeTutorial 52 | 53 | https://cmake.org/cmake/help/latest/command/install.html -------------------------------------------------------------------------------- /other/cookie/readme.md: -------------------------------------------------------------------------------- 1 | ## SameSite 2 | 3 | https://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html 4 | 5 | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite 6 | 7 | https://github.com/mqyqingfeng/Blog/issues/157 8 | 9 | https://datatracker.ietf.org/doc/html/rfc6265#section-4.1 -------------------------------------------------------------------------------- /other/cors/readme.md: -------------------------------------------------------------------------------- 1 | ## CORS 2 | 3 | CORS由一系列传输的HTTP头组成,这些HTTP头有两个作用, 4 | 5 | 1:用于阻止还是允许浏览器向其他域名发起请求; 6 | 7 | 2:用于接受还是拒绝其他域名返回的响应数据; 8 | 9 | 跨域是浏览器正确做出请求,服务器也能正确做出响应,是浏览器拒绝接收跨域服务器返回的数据 10 | 11 | ### 12 | 13 | 很多人也认为使用CORS解决跨域很简单,只需要在服务器添加响应头 “ Access-Control-Allow-Origin :* ” 就可以了, 14 | 15 | 在CORS中,所有的跨域请求被分为了两种类型,一种是简单请求,一种是复杂请求 (严格来说应该叫‘需预检请求’); 16 | 17 | 简单请求与普通的ajax请求无异; 18 | 19 | 但复杂请求,必须在正式发送请求前先发送一个OPTIONS方法的请求已得到服务器的同意,若没有得到服务器的同意,浏览器不会发送正式请求; 20 | 21 | ## Conclusion 22 | 23 | 出于安全性的考虑,浏览器引入同源策略; 24 | 25 | CORS本质上就是使用各种头信息来是浏览器与服务器之间进行身份认证实现跨域数据共享; 26 | 27 | CORS中最常使用的响应头为 Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Expose-Headers; 28 | 29 | CORS中最常使用的请求头为 Origin、Access-Control-Request-Headers、Access-Control-Request-Method; 30 | 31 | ## 简单类型的请求 32 | 33 | 1:请求方法必须是 GET、HEAD、POST中的一种,其他方法不行; 34 | 35 | 2:请求头类型只能是 Accept、Accept-Language、Content-Language、Content-Type,添加其他额外请求头不行; 36 | 37 | 3:请求头 Content-Type 如果有,值只能是 text/plain、multipart/form-data、application/x-www-form-urlencoded 中的一种,其他值不行; 38 | 39 | 4:请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; 40 | 41 | 5:请求中没有使用 ReadableStream 对象 42 | 43 | ## ref 44 | 45 | https://zhuanlan.zhihu.com/p/53996160 46 | 47 | https://www.ruanyifeng.com/blog/2016/04/cors.html 48 | 49 | -------------------------------------------------------------------------------- /other/dns/02_dns.md: -------------------------------------------------------------------------------- 1 | ## dns 2 | 3 | 1. What is dns 4 | 5 | 2. Why we need dns 6 | 7 | 3. dns查询过程 8 | 9 | dig url 10 | 11 | ## DNS应用层协议 12 | 13 | 1. DNS资源记录 14 | 15 | 2. TYPE 16 | 17 | 3. 协议细节 18 | 19 | ## ref 20 | 21 | https://www.cnblogs.com/dongkuo/p/6714071.html 22 | 23 | https://www.ruanyifeng.com/blog/2016/06/dns.html 24 | 25 | https://zhuanlan.zhihu.com/p/31568450 26 | 27 | https://zhuanlan.zhihu.com/p/78606595 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /other/dns/03_dns_linux.md: -------------------------------------------------------------------------------- 1 | ## Linux下域名解析配置 2 | 3 | https://www.jianshu.com/p/2c1c081cc521 4 | 5 | Linux系统下域名解析的配置文件是/etc/resolv.conf 6 | 7 | ## Linux resolv.conf简介 8 | 9 | campus.pingcap.com/campus_apply/pingcap/39951/#/?anchorName=default_joblist&sourceToken= 10 | 11 | ### 域名系统解析器(DNS Resolver 12 | 13 | man 3 resolver 14 | 15 | ### resolv.conf:search、domain、nameserver解释 16 | 17 | http://www.ttlsa.com/linux/resolv-conf-desc/ 18 | 19 | ## 简单的dns协议解析 20 | 21 | https://zhuanlan.zhihu.com/p/78606595 22 | 23 | 24 | ## DNS常用记录类型和服务发现(DNS解析) 25 | 26 | https://blog.csdn.net/u012206617/article/details/106577713 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /other/dns/04_http_dns.md: -------------------------------------------------------------------------------- 1 | ## httpdns 2 | 3 | ## 阿里云httpdns 4 | 5 | https://www.aliyun.com/product/httpdns 6 | 7 | ## httpdns lib 8 | 9 | https://github.com/CNSRE/HTTPDNSLib 10 | 11 | ## 【鹅厂网事】全局精确流量调度新思路-HttpDNS服务详解 12 | 13 | https://mp.weixin.qq.com/s?__biz=MzA3ODgyNzcwMw==&mid=201837080&idx=1&sn=b2a152b84df1c7dbd294ea66037cf262&scene=2&from=timeline&isappinstalled=0&utm_source=tuicool 14 | 15 | localDNS经常出问题的几点原因 -------------------------------------------------------------------------------- /other/global/a.h: -------------------------------------------------------------------------------- 1 | #ifndef A_H 2 | #define A_H 3 | 4 | #include "global.h" 5 | 6 | inline void func() 7 | { 8 | fprintf(stderr, "addr1 : %p\n", &gobal_str); 9 | } 10 | 11 | 12 | 13 | #endif // A_H -------------------------------------------------------------------------------- /other/global/global.cc: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | 3 | const std::string gobal_str = "sk mit"; -------------------------------------------------------------------------------- /other/global/global.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL_H 2 | #define GLOBAL_H 3 | 4 | #include 5 | 6 | extern const std::string gobal_str; 7 | 8 | #endif // GLOBAL_H -------------------------------------------------------------------------------- /other/global/main.cc: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "a.h" 3 | 4 | int main() 5 | { 6 | func(); 7 | fprintf(stderr, "addr2 : %p\n", &gobal_str); 8 | } -------------------------------------------------------------------------------- /other/http_router/readme.md: -------------------------------------------------------------------------------- 1 | ## part1 : router 对比 2 | 3 | -------------------------------------------------------------------------------- /other/inherit/01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Base { 5 | public: 6 | void f(int a){ 7 | cout << "Base::f(int a)" << endl; 8 | } 9 | virtual void g(int a) { 10 | cout << "virtual Base::g(int a)" << endl; 11 | } 12 | }; 13 | 14 | class Derived : public Base 15 | { 16 | public: 17 | void h(int a) { 18 | cout << "Derivd::h(int a)" << endl; 19 | } 20 | }; 21 | 22 | int main() 23 | { 24 | Base b; 25 | b.f(3); 26 | b.g(4); 27 | 28 | Derived d; 29 | d.f(3); 30 | d.g(4); 31 | d.h(3); 32 | } -------------------------------------------------------------------------------- /other/inherit/02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Base { 5 | public: 6 | void f(int a){ 7 | cout << "Base::f(int a)" << endl; 8 | } 9 | virtual void g(int a) { 10 | cout << "virtual Base::g(int a)" << endl; 11 | } 12 | }; 13 | 14 | class Derived : public Base 15 | { 16 | public: 17 | void h(int a) { 18 | cout << "Derivd::h(int a)" << endl; 19 | } 20 | virtual void g(int a) { 21 | cout << "virtual Derived::g(int a)" << endl; 22 | } 23 | }; 24 | 25 | int main() 26 | { 27 | Base b; 28 | b.f(3); 29 | b.g(4); 30 | 31 | Derived d; 32 | d.f(3); 33 | d.g(4); 34 | d.h(3); 35 | } 36 | -------------------------------------------------------------------------------- /other/inherit/03.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Base { 5 | public: 6 | virtual void f(float x) { 7 | cout << "virtual Base::f(float) " << x << endl; 8 | } 9 | void g(float x) { 10 | cout << "Base::g(float) " << x << endl; 11 | } 12 | void h(float x) { 13 | cout << "Base::h(float) " << x << endl; 14 | } 15 | }; 16 | 17 | class Derived : public Base { 18 | public: 19 | virtual void f(float x) { 20 | cout << "virtual Derived::f(float) " << x << endl; 21 | } 22 | void g(int x) { 23 | cout << "Derived::g(int) " << x << endl; 24 | } 25 | void h(float x) { 26 | cout << "Derived::h(float) " << x << endl; 27 | } 28 | }; 29 | 30 | int main(void) 31 | { 32 | Derived d; 33 | Base *pb = &d; 34 | Derived *pd = &d; 35 | 36 | pb->f(3.14f); 37 | pd->f(3.14f); 38 | 39 | pb->g(3.14f); 40 | pd->g(3.14f); 41 | 42 | pb->h(3.14f); 43 | pd->h(3.14f); 44 | } -------------------------------------------------------------------------------- /other/inherit/04.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class Base { 5 | public: 6 | void g(float x) { 7 | cout << "Base::g(float) " << x << endl; 8 | } 9 | }; 10 | 11 | class Derived : public Base { 12 | private: 13 | void g(int x) { 14 | cout << "Derived::g(int) " << x << endl; 15 | } 16 | }; 17 | 18 | int main(void) 19 | { 20 | Derived d; 21 | Base *pb = &d; 22 | Derived *pd = &d; 23 | 24 | pb->g(3.14f); 25 | // pd->g(3); 26 | } -------------------------------------------------------------------------------- /other/inl_file/A.h: -------------------------------------------------------------------------------- 1 | #ifndef A_H 2 | #define A_H 3 | 4 | class A 5 | { 6 | public: 7 | template 8 | void test(T t); 9 | }; 10 | 11 | #include "A.inl" 12 | 13 | #endif // A_H -------------------------------------------------------------------------------- /other/inl_file/A.inl: -------------------------------------------------------------------------------- 1 | #include 2 | #include "A.h" 3 | 4 | template 5 | void A::test(T t) 6 | { 7 | std::cout << t << std::endl; 8 | } 9 | 10 | class B 11 | { 12 | public: 13 | template 14 | void test(T t) 15 | { 16 | std::cout << t << std::endl; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /other/inl_file/main.cc: -------------------------------------------------------------------------------- 1 | #include "A.h" 2 | 3 | int main() 4 | { 5 | A a; 6 | a.test(1); 7 | B b; 8 | b.test(2); 9 | } -------------------------------------------------------------------------------- /other/lambda/01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | int *a = new int(10); 7 | auto f = [&a] { 8 | cout << *a << endl; 9 | delete a; 10 | }; 11 | double *b = new double(2.0); 12 | auto f1 = [=] { 13 | cout << *b << endl; 14 | delete b; 15 | }; 16 | double *c = new double(3.0); 17 | auto f2 = [c] { 18 | cout << *c << endl; 19 | delete c; 20 | }; 21 | cout << "test" << endl; 22 | f(); 23 | f1(); 24 | f2(); 25 | } -------------------------------------------------------------------------------- /other/map_case_intensive/test01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::string; 7 | using std::map; 8 | using std::cout; 9 | using std::endl; 10 | 11 | // recommended in Meyers, Effective STL when internationalization and embedded 12 | // NULLs aren't an issue. Much faster than the STL or Boost lex versions. 13 | struct ciLessLibC : public std::binary_function { 14 | bool operator()(const string &lhs, const string &rhs) const { 15 | return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ; 16 | } 17 | }; 18 | 19 | typedef map< string, int, ciLessLibC> mapLibc_t; 20 | 21 | int main(void) { 22 | mapLibc_t cisMap; // change to test other comparitor 23 | 24 | cisMap["foo"] = 1; 25 | cisMap["FOO"] = 2; 26 | 27 | cisMap["bar"] = 3; 28 | cisMap["BAR"] = 4; 29 | 30 | cisMap["baz"] = 5; 31 | cisMap["BAZ"] = 6; 32 | 33 | cout << "foo == " << cisMap["foo"] << endl; 34 | cout << "bar == " << cisMap["bar"] << endl; 35 | cout << "baz == " << cisMap["baz"] << endl; 36 | 37 | if(cisMap.count("FoO")) cout << "has foo" << endl; 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /other/map_case_intensive/test02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::string; 7 | using std::map; 8 | using std::cout; 9 | using std::endl; 10 | 11 | struct ci_less 12 | { 13 | // case-independent (ci) compare_less binary function 14 | struct nocase_compare 15 | { 16 | bool operator() (const unsigned char& c1, const unsigned char& c2) const { 17 | return tolower (c1) < tolower (c2); 18 | } 19 | }; 20 | bool operator() (const std::string & s1, const std::string & s2) const { 21 | return std::lexicographical_compare 22 | (s1.begin (), s1.end (), // source range 23 | s2.begin (), s2.end (), // dest range 24 | nocase_compare ()); // comparison 25 | } 26 | }; 27 | 28 | typedef map< string, int, ci_less> mapLibc_t; 29 | 30 | int main(void) { 31 | mapLibc_t cisMap; // change to test other comparitor 32 | 33 | cisMap["foo"] = 1; 34 | cisMap["FOO"] = 2; 35 | 36 | cisMap["bar"] = 3; 37 | cisMap["BAR"] = 4; 38 | 39 | cisMap["baz"] = 5; 40 | cisMap["BAZ"] = 6; 41 | 42 | cout << "foo == " << cisMap["foo"] << endl; 43 | cout << "bar == " << cisMap["bar"] << endl; 44 | cout << "baz == " << cisMap["baz"] << endl; 45 | 46 | if(cisMap.count("FoO")) cout << "has foo" << endl; 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /other/mysql/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/other/mysql/readme.md -------------------------------------------------------------------------------- /other/name_service/05_name_service.md: -------------------------------------------------------------------------------- 1 | ## name service 2 | 3 | https://github.com/apache/incubator-brpc/blob/master/docs/cn/load_balancing.md#%E5%91%BD%E5%90%8D%E6%9C%8D%E5%8A%A1 4 | -------------------------------------------------------------------------------- /other/post/multipart-parser-c.md: -------------------------------------------------------------------------------- 1 | ## multipart-parser-c using in wfrest 2 | 3 | https://github.com/iafonov/multipart-parser-c 4 | 5 | https://github.com/chanchann/wfrest/blob/main/src/HttpContent.h 6 | 7 | ## parse_multipart 8 | 9 | 我们从核心接口出发,看如何parse_multipart data的 10 | 11 | ```cpp 12 | std::string boundary = "--" + boundary_; 13 | multipart_parser *parser = multipart_parser_init(boundary.c_str(), &settings_); 14 | ``` 15 | 16 | 我们header中给出的boudary 前面加上 "--" 作为下面part的boundary 17 | 18 | -------------------------------------------------------------------------------- /other/relpath/test.cc: -------------------------------------------------------------------------------- 1 | #include /* PATH_MAX */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int main(void) { 9 | char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */ 10 | char *res = realpath("text.txt", buf); 11 | if (res) { // or: if (res != NULL)123 12 | printf("This source is at %s\n", buf); 13 | } else { 14 | char* errStr = strerror(errno); 15 | printf("error string: %s\n", errStr); 16 | 17 | perror("realpath"); 18 | exit(EXIT_FAILURE); 19 | } 20 | return 0; 21 | } -------------------------------------------------------------------------------- /other/relpath/text.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/other/relpath/text.txt -------------------------------------------------------------------------------- /other/size/01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test(size_t a) 4 | { 5 | std::cout << a << std::endl; 6 | if(a == -1) 7 | { 8 | std::cout << "-1" << std::endl; 9 | } else if(a == -3) 10 | { 11 | std::cout << "-3" << std::endl; 12 | } 13 | int end = 10; 14 | int start = end + a; 15 | std::cout << "start : " << start << std::endl; 16 | 17 | } 18 | 19 | int main() 20 | { 21 | test(1); 22 | test(-1); 23 | test(-3); 24 | } -------------------------------------------------------------------------------- /other/size/02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test(size_t a) 4 | { 5 | std::cout << a << std::endl; 6 | size_t end = 10; 7 | size_t start = end + a; 8 | std::cout << "start : " << start << " end : " << end << std::endl; 9 | } 10 | 11 | int main() 12 | { 13 | test(-12); 14 | 15 | } -------------------------------------------------------------------------------- /other/size/03.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test(size_t a_1) 4 | { 5 | int a = a_1; 6 | if(a < 0) 7 | std::cout << "less than 0" << std::endl; 8 | std::cout << a << std::endl; 9 | int end = 10; 10 | int start = end + a; 11 | std::cout << "start : " << start << " end : " << end << std::endl; 12 | } 13 | 14 | int main() 15 | { 16 | test(-12); 17 | 18 | } -------------------------------------------------------------------------------- /other/test/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void test(const std::vector &vec) 5 | { 6 | for(auto v : vec) 7 | { 8 | std::cout << v << std::endl; 9 | } 10 | } 11 | 12 | int main() 13 | { 14 | test({1,2,3,4}); 15 | } -------------------------------------------------------------------------------- /other/time/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std::chrono; 6 | 7 | int main() 8 | { 9 | uint64_t ms_since_epoch = duration_cast(system_clock::now().time_since_epoch()).count(); 10 | time_t sec = static_cast(ms_since_epoch / 1000000); 11 | struct tm tm_time; 12 | char time_str_utc[64]; 13 | ::gmtime_r(&sec, &tm_time); 14 | 15 | int len = snprintf(time_str_utc, sizeof time_str_utc, "%4d-%02d-%02d_%02d:%02d:%02d", 16 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 17 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 18 | std::cout << time_str_utc << " UTC" << std::endl; 19 | 20 | char time_str_local[64]; 21 | ::localtime_r(&sec, &tm_time); 22 | int len2 = snprintf(time_str_local, sizeof time_str_local, "%4d-%02d-%02d_%02d:%02d:%02d", 23 | tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, 24 | tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); 25 | std::cout << time_str_local << " local" << std::endl; 26 | return 0; 27 | } -------------------------------------------------------------------------------- /other/todo.md: -------------------------------------------------------------------------------- 1 | 1. 资源池demo 2 | 3 | 2. kernel代码梳理 4 | 5 | 3. 测压 6 | 7 | 4. dns -------------------------------------------------------------------------------- /other/unordered_map/01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::unordered_map map; 7 | map["123"] = "abc"; 8 | map["4"] = "d"; 9 | auto var1 = map["123"]; 10 | std::cout << "va1 : " << var1 << std::endl; 11 | // auto var2 = map.at("unkonw"); // throw exeption 12 | auto var2 = map["unknow"]; 13 | std::cout << "var2 : " << var2 << std::endl; 14 | return 0; 15 | } -------------------------------------------------------------------------------- /other/unordered_map/02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::unordered_map map; 7 | map["123"] = "abc"; 8 | map["4"] = "d"; 9 | 10 | std::unordered_map map2; 11 | 12 | map2 = std::move(map); 13 | 14 | for(auto &m : map2) 15 | { 16 | std::cout << m.first << " : " << m.second << std::endl; 17 | } 18 | return 0; 19 | } -------------------------------------------------------------------------------- /other/web_template/readme.md: -------------------------------------------------------------------------------- 1 | ## web template 2 | 3 | template 还是很常见的,但是与以往不太一样了 4 | 5 | 以前的 template 是直接把处理好的数据塞进 html 里生成视图丢给客户端 6 | 7 | 现在的 template 仅用于一些不方便通过二次请求拿的数据,服务端会直接通过 template 塞到 html 里 8 | 9 | 比如私有化部署、海内外环境区分啥的,有的身份凭证也会通过 template 植入 10 | -------------------------------------------------------------------------------- /other/wfrest_exp/pics/cookie01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/other/wfrest_exp/pics/cookie01.png -------------------------------------------------------------------------------- /other/wfrest_exp/pics/cookie02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/other/wfrest_exp/pics/cookie02.png -------------------------------------------------------------------------------- /other/wfrest_exp/pics/cookie03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/other/wfrest_exp/pics/cookie03.png -------------------------------------------------------------------------------- /src_analysis/03_communicate.md: -------------------------------------------------------------------------------- 1 | ## 通信大致流程 2 | 3 | ``` 4 | handle 5 | ├── Communicator::handle_incoming_request [vim src/kernel/Communicator.cc +541] 6 | ├── Communicator::handle_incoming_reply [vim src/kernel/Communicator.cc +619] 7 | ├── Communicator::handle_reply_result [vim src/kernel/Communicator.cc +712] 8 | ├── Communicator::handle_request_result [vim src/kernel/Communicator.cc +774] 9 | ├── Communicator::handle_connect_result [vim src/kernel/Communicator.cc +930] 10 | ├── Communicator::handle_sleep_result [vim src/kernel/Communicator.cc +1031] 11 | ├── Communicator::handle_aio_result [vim src/kernel/Communicator.cc +1044] 12 | ├── Communicator::reply [vim src/kernel/Communicator.cc +1641] 13 | ├── IOService::decref [vim src/kernel/IOService_thread.cc +114] 14 | ├── IOService::decref [vim src/kernel/IOService_linux.cc +286] 15 | ├── Executor::executor_thread_routine [vim src/kernel/Executor.cc +76] 16 | ├── Executor::executor_cancel_tasks [vim src/kernel/Executor.cc +102] 17 | └── handle [vim src/factory/HttpTaskImpl.cc +840] 18 | ``` 19 | 20 | 发来消息,则handle 21 | -------------------------------------------------------------------------------- /src_analysis/05_poller_opt.md: -------------------------------------------------------------------------------- 1 | ## poller的优化 2 | 3 | https://github.com/sogou/workflow/pull/553/files -------------------------------------------------------------------------------- /src_analysis/06_dns_01.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/06_dns_01.md -------------------------------------------------------------------------------- /src_analysis/06_dns_03.md: -------------------------------------------------------------------------------- 1 | # workflow源码解析12 : dns 03 2 | 3 | 我们来看看dns_cache到底是如何使用的 4 | 5 | 我们先看看出现在什么地方 6 | 7 | ![cache](./pics/dns_cache_04.png) 8 | 9 | 就只出现在了两个地方 10 | 11 | 1. void WFResolverTask::() 12 | 13 | 此处已经分析过了 14 | 15 | 2. void WFResolverTask::dns_single_callback(WFDnsTask *dns_task) 16 | 17 | -------------------------------------------------------------------------------- /src_analysis/06_dns_protocol.md: -------------------------------------------------------------------------------- 1 | ## dns protocol 2 | 3 | ![dns protocol](./pics/dns_protocol.png) 4 | 5 | DnsRequest和DnsResponse 继承自 DnsMessage 6 | 7 | 我们的request就是设置好question 8 | -------------------------------------------------------------------------------- /src_analysis/06_dns_routine.md: -------------------------------------------------------------------------------- 1 | # workflow源码解析14 : DnsRoutine 2 | 3 | ## DnsInput 4 | 5 | ```cpp 6 | class DnsInput 7 | { 8 | public: 9 | ... 10 | void reset(const std::string& host, unsigned short port) 11 | { 12 | host_.assign(host); 13 | port_ = port; 14 | } 15 | protected: 16 | std::string host_; 17 | unsigned short port_; 18 | ... 19 | }; 20 | ``` 21 | 22 | 主要就是存我们需要dns解析的host和port 23 | 24 | ## DnsOutput 25 | 26 | ```cpp 27 | 28 | class DnsOutput 29 | { 30 | public: 31 | ... 32 | 33 | protected: 34 | int error_; 35 | struct addrinfo *addrinfo_; 36 | ... 37 | }; 38 | ``` 39 | 40 | 我们想到的的dns output就是addrinfo 41 | 42 | ## DnsRoutine 43 | 44 | 其中,如何从DnsInput 到 DnsOutput 的过程是 DnsRoutine 45 | 46 | ```cpp 47 | class DnsRoutine 48 | { 49 | public: 50 | static void run(const DnsInput *in, DnsOutput *out); 51 | static void create(DnsOutput *out, int error, struct addrinfo *ai) 52 | { 53 | if (out->addrinfo_) 54 | freeaddrinfo(out->addrinfo_); 55 | 56 | out->error_ = error; 57 | out->addrinfo_ = ai; 58 | } 59 | 60 | private: 61 | static void run_local_path(const std::string& path, DnsOutput *out); 62 | }; 63 | 64 | ``` 65 | 66 | ## DnsRoutine::run 67 | 68 | 其中比较重要的就是这个run,最终是在这里通过getaddrinfo 通过host, port 获取到addrino 69 | 70 | ```cpp 71 | void DnsRoutine::run(const DnsInput *in, DnsOutput *out) 72 | { 73 | if (!in->host_.empty() && in->host_[0] == '/') 74 | { 75 | run_local_path(in->host_, out); 76 | return; 77 | } 78 | 79 | struct addrinfo hints = { 80 | #ifdef AI_ADDRCONFIG 81 | .ai_flags = AI_ADDRCONFIG, 82 | #endif 83 | .ai_family = AF_UNSPEC, 84 | .ai_socktype = SOCK_STREAM 85 | }; 86 | char port_str[PORT_STR_MAX + 1]; 87 | 88 | snprintf(port_str, PORT_STR_MAX + 1, "%u", in->port_); 89 | out->error_ = getaddrinfo(in->host_.c_str(), 90 | port_str, 91 | &hints, 92 | &out->addrinfo_); 93 | } 94 | 95 | ``` 96 | 97 | 这里如果是local path,以'/'开头,那么就调用`run_local_path`,我们暂时先不管 -------------------------------------------------------------------------------- /src_analysis/13_concept.md: -------------------------------------------------------------------------------- 1 | ## wf的一些设计 2 | 3 | ## 算法与协议的对称性 4 | 5 | 有自定义算法的线程任务,也存在自定义协议的网络任务 6 | 7 | 自定义算法要求提供算法的过程 8 | 9 | 而自定义协议则需要用户提供序列化和反序列化的过程 10 | 11 | 算法就是一个从INPUT到OUPUT的转换过程,算法并不知道task,series等的存在。 12 | 13 | HTTP协议的实现上,也只关心序列化反序列化,无需要关心什么是task。而是在http task里去引用HTTP协议。 14 | 15 | -------------------------------------------------------------------------------- /src_analysis/19_resource_pool_01.md: -------------------------------------------------------------------------------- 1 | # workflow 源码解析 10 : 资源池 - WFResourcePool 02 2 | 3 | 项目源码 : https://github.com/sogou/workflow 4 | 5 | 更加详细的源码注释可看 : https://github.com/chanchann/workflow_annotation 6 | 7 | 相关文档 : https://github.com/sogou/workflow/blob/master/docs/about-conditional.md 8 | 9 | 接下来我们给出更多的demo,更加灵活应用WFResourcePool 10 | 11 | ## -------------------------------------------------------------------------------- /src_analysis/21_rb_tree_opt.md: -------------------------------------------------------------------------------- 1 | # rbtree opt 2 | 3 | https://github.com/sogou/workflow/pull/602/commits/a015bc523d9fc36bc465a01b882e828a98834b65 4 | 5 | ## 参考stl的map实现 6 | -------------------------------------------------------------------------------- /src_analysis/26_http_parser.md: -------------------------------------------------------------------------------- 1 | # workflow 源码解析 : 如何手写http parser 2 | 3 | 项目源码 : https://github.com/sogou/workflow 4 | 5 | 更加详细的源码注释可看 : https://github.com/chanchann/workflow_annotation 6 | 7 | ## -------------------------------------------------------------------------------- /src_analysis/pics/CommSchedObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/CommSchedObject.png -------------------------------------------------------------------------------- /src_analysis/pics/UMLClassDiagram-WFTaskFactory-inl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/UMLClassDiagram-WFTaskFactory-inl.png -------------------------------------------------------------------------------- /src_analysis/pics/appen_list.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/appen_list.jpeg -------------------------------------------------------------------------------- /src_analysis/pics/dns_cache_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/dns_cache_01.png -------------------------------------------------------------------------------- /src_analysis/pics/dns_cache_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/dns_cache_02.png -------------------------------------------------------------------------------- /src_analysis/pics/dns_cache_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/dns_cache_03.png -------------------------------------------------------------------------------- /src_analysis/pics/dns_cache_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/dns_cache_04.png -------------------------------------------------------------------------------- /src_analysis/pics/dns_protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/dns_protocol.png -------------------------------------------------------------------------------- /src_analysis/pics/exeReuest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/exeReuest.png -------------------------------------------------------------------------------- /src_analysis/pics/http01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/http01.png -------------------------------------------------------------------------------- /src_analysis/pics/json_arr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/json_arr.png -------------------------------------------------------------------------------- /src_analysis/pics/json_num.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/json_num.png -------------------------------------------------------------------------------- /src_analysis/pics/json_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/json_obj.png -------------------------------------------------------------------------------- /src_analysis/pics/json_str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/json_str.png -------------------------------------------------------------------------------- /src_analysis/pics/json_val.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/json_val.png -------------------------------------------------------------------------------- /src_analysis/pics/message_out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/message_out.png -------------------------------------------------------------------------------- /src_analysis/pics/message_out01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/message_out01.png -------------------------------------------------------------------------------- /src_analysis/pics/mysql_io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/mysql_io.png -------------------------------------------------------------------------------- /src_analysis/pics/networktask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/networktask.png -------------------------------------------------------------------------------- /src_analysis/pics/subtask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/subtask.png -------------------------------------------------------------------------------- /src_analysis/pics/subtasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/subtasks.png -------------------------------------------------------------------------------- /src_analysis/pics/task_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chanchann/workflow_annotation/8b7e8c43d6fd4de4320b248cb196984c6c68f4cf/src_analysis/pics/task_arch.png -------------------------------------------------------------------------------- /workflow/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 -------------------------------------------------------------------------------- /workflow/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # bazel env 35 | bazel-* 36 | -------------------------------------------------------------------------------- /workflow/.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | dist: trusty 3 | os: linux 4 | compiler: 5 | - gcc 6 | 7 | jobs: 8 | include: 9 | - env: COMPILER=g++-8 BUILD=Release STANDARD=11 10 | compiler: gcc 11 | addons: 12 | apt: 13 | update: true 14 | sources: 15 | - ubuntu-toolchain-r-test 16 | packages: 17 | - g++-8 18 | - cmake 19 | 20 | script: 21 | - make 22 | - cd tutorial 23 | - make 24 | -------------------------------------------------------------------------------- /workflow/benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "build type") 4 | 5 | project(benchmark 6 | LANGUAGES C CXX 7 | ) 8 | 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) 10 | 11 | find_library(LIBRT rt) 12 | find_package(OpenSSL REQUIRED) 13 | find_package(workflow REQUIRED CONFIG HINTS ..) 14 | include_directories(${OPENSSL_INCLUDE_DIR} ${WORKFLOW_INCLUDE_DIR}) 15 | link_directories(${WORKFLOW_LIB_DIR}) 16 | 17 | if (WIN32) 18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP /wd4200") 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4200 /std:c++14") 20 | else () 21 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIC -pipe -std=gnu90") 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fPIC -pipe -std=c++11 -fno-exceptions") 23 | endif () 24 | 25 | set(BENCHMARK_LIST 26 | benchmark-01-http_server 27 | benchmark-02-http_server_long_req 28 | ) 29 | 30 | if (APPLE) 31 | set(WORKFLOW_LIB workflow pthread z OpenSSL::SSL OpenSSL::Crypto) 32 | else () 33 | set(WORKFLOW_LIB workflow ${LIBRT}) 34 | endif () 35 | 36 | foreach(src ${BENCHMARK_LIST}) 37 | string(REPLACE "-" ";" arr ${src}) 38 | list(GET arr -1 bin_name) 39 | add_executable(${bin_name} ${src}.cc) 40 | target_link_libraries(${bin_name} ${WORKFLOW_LIB}) 41 | endforeach() 42 | -------------------------------------------------------------------------------- /workflow/benchmark/benchmark-01-http_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "util/args.h" 8 | #include "util/content.h" 9 | #include "util/date.h" 10 | 11 | static WFFacilities::WaitGroup wait_group{1}; 12 | 13 | void signal_handler(int) 14 | { 15 | wait_group.done(); 16 | } 17 | 18 | int main(int argc, char ** argv) 19 | { 20 | size_t pollers; 21 | unsigned short port; 22 | size_t length; 23 | 24 | if (parse_args(argc, argv, pollers, port, length) != 3) 25 | { 26 | return -1; 27 | } 28 | 29 | std::signal(SIGINT, signal_handler); 30 | std::signal(SIGTERM, signal_handler); 31 | 32 | WFGlobalSettings settings = GLOBAL_SETTINGS_DEFAULT; 33 | settings.poller_threads = pollers; 34 | WORKFLOW_library_init(&settings); 35 | 36 | const std::string content = make_content(length); 37 | WFHttpServer server([&content](WFHttpTask * task) 38 | { 39 | auto * resp = task->get_resp(); 40 | 41 | char timestamp[32]; 42 | date(timestamp, sizeof(timestamp)); 43 | resp->add_header_pair("Date", timestamp); 44 | 45 | resp->add_header_pair("Content-Type", "text/plain; charset=UTF-8"); 46 | 47 | resp->append_output_body_nocopy(content.data(), content.size()); 48 | }); 49 | 50 | if (server.start(port) == 0) 51 | { 52 | wait_group.wait(); 53 | server.stop(); 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /workflow/benchmark/benchmark-02-http_server_long_req.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util/args.h" 9 | #include "util/content.h" 10 | #include "util/date.h" 11 | 12 | static WFFacilities::WaitGroup wait_group{1}; 13 | 14 | void signal_handler(int) 15 | { 16 | wait_group.done(); 17 | } 18 | 19 | int main(int argc, char ** argv) 20 | { 21 | size_t pollers; 22 | unsigned short port; 23 | size_t length; 24 | size_t microseconds; 25 | 26 | if (parse_args(argc, argv, pollers, port, length, microseconds) != 4) 27 | { 28 | return -1; 29 | } 30 | 31 | std::signal(SIGINT, signal_handler); 32 | std::signal(SIGTERM, signal_handler); 33 | 34 | WFGlobalSettings settings = GLOBAL_SETTINGS_DEFAULT; 35 | settings.poller_threads = pollers; 36 | WORKFLOW_library_init(&settings); 37 | 38 | const std::string content = make_content(length); 39 | WFHttpServer server([&content, µseconds](WFHttpTask * task) 40 | { 41 | auto resp = task->get_resp(); 42 | 43 | char timestamp[32]; 44 | date(timestamp, sizeof(timestamp)); 45 | resp->add_header_pair("Date", timestamp); 46 | 47 | resp->add_header_pair("Content-Type", "text/plain; charset=UTF-8"); 48 | 49 | resp->append_output_body_nocopy(content.data(), content.size()); 50 | 51 | auto req = task->get_req(); 52 | auto uri = req->get_request_uri(); 53 | if (std::strcmp(uri, "/long_req/") == 0) 54 | { 55 | auto timer_task = WFTaskFactory::create_timer_task(microseconds, nullptr); 56 | series_of(task)->push_back(timer_task); 57 | } 58 | }); 59 | 60 | if (server.start(port) == 0) 61 | { 62 | wait_group.wait(); 63 | server.stop(); 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /workflow/benchmark/util/content.h: -------------------------------------------------------------------------------- 1 | #ifndef _BENCHMARK_CONTENT_H_ 2 | #define _BENCHMARK_CONTENT_H_ 3 | 4 | #include 5 | #include 6 | 7 | static inline std::string make_content(size_t length) 8 | { 9 | std::mt19937_64 gen{42}; 10 | std::uniform_int_distribution dis{32, 126}; 11 | 12 | std::string s; 13 | s.reserve(length); 14 | for (size_t i = 0; i < length; i++) 15 | { 16 | s.push_back(static_cast(dis(gen))); 17 | } 18 | return s; 19 | } 20 | 21 | #endif //_BENCHMARK_CONTENT_H_ 22 | -------------------------------------------------------------------------------- /workflow/benchmark/util/date.h: -------------------------------------------------------------------------------- 1 | #ifndef _BENCHMARK_DATE_H_ 2 | #define _BENCHMARK_DATE_H_ 3 | 4 | #include 5 | 6 | static inline void date(char * buf, size_t n) 7 | { 8 | auto tt = std::time(nullptr); 9 | std::tm cur{}; 10 | // gmtime_r(&tt, &cur); 11 | localtime_r(&tt, &cur); 12 | strftime(buf, n, "%a, %d %b %Y %H:%M:%S %Z", &cur); 13 | } 14 | 15 | #endif //_BENCHMARK_DATE_H_ 16 | -------------------------------------------------------------------------------- /workflow/build.cmake/config.toinstall.cmake: -------------------------------------------------------------------------------- 1 | 2 | ####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### 3 | ####### Any changes to this file will be overwritten by the next CMake run #### 4 | ####### The input file was workflow-config.cmake.in ######## 5 | 6 | get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) 7 | 8 | macro(set_and_check _var _file) 9 | set(${_var} "${_file}") 10 | if(NOT EXISTS "${_file}") 11 | message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") 12 | endif() 13 | endmacro() 14 | 15 | macro(check_required_components _NAME) 16 | foreach(comp ${${_NAME}_FIND_COMPONENTS}) 17 | if(NOT ${_NAME}_${comp}_FOUND) 18 | if(${_NAME}_FIND_REQUIRED_${comp}) 19 | set(${_NAME}_FOUND FALSE) 20 | endif() 21 | endif() 22 | endforeach() 23 | endmacro() 24 | 25 | #################################################################################### 26 | 27 | set(WORKFLOW_VERSION "0.9.7") 28 | set_and_check(WORKFLOW_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include") 29 | set_and_check(WORKFLOW_LIB_DIR "${PACKAGE_PREFIX_DIR}/lib") 30 | 31 | if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 32 | include ("${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 33 | endif () 34 | 35 | check_required_components(workflow) 36 | -------------------------------------------------------------------------------- /workflow/docs/about-exit.md: -------------------------------------------------------------------------------- 1 | # 关于程序退出 2 | 3 | 由于我们的大多数调用都是非阻塞的,所以在之前的示例里我们都需要用一些机制来防止main函数提前退出。 4 | 例如wget示例中等待用户的Ctrl-C,或者像parallel_wget在所有抓取结束之后唤醒主线程。 5 | 而在几个server的示例中,stop()操作是阻塞的,可以确保所有server task的正常结束,主线程可安全退出。 6 | 7 | # 程序安全退出的原则 8 | 9 | 一般情况下,用户只要正常写程序,模仿示例中的方法,不太会有什么关于退出的疑惑。但这里还是需要把程序正常退出的条件定义好。 10 | * 用户不可以在callback或process等任何回调函数里调用系统的exit()函数,否则行为无定义。 11 | * 主线程可以安全结束(main函数调用exit()或return)的条件是所有任务已经运行到callback,并且没有新的任务被调起。 12 | * 我们所有的示例都符合这个假设,在callback里唤醒main函数。这是安全的,不用担心main返回的时候,callback还没结束的情况。 13 | * ParallelWork是一种task,也需要运行到callback。 14 | * 这一条规则某下情况下可以违反,并且程序行为有严格定义。但不了解核心原理的使用者请遵守这条规则,否则程序无法正常退出。 15 | * 所有server必须stop完成,否则行为无定义。因为stop操作用户都会调,所以一般server程序不会有什么退出方面的问题。 16 | * server的stop会等待所有server task所在series结束。但如果用户在process直接start一个新任务,则需要自己考虑任务结束的问题。 17 | 18 | # 关于OpenSSL 1.1版本在退出时的内存泄露 19 | 20 | 我们发现某些openssl1.1版本,存在退出时内存释放不完全的问题,通过valgrind内存检查工具可以看出内存泄露。 21 | 这个问题只有在用户使用了SSL,例如抓取了https网页时才会发生,而且一般情况下用户可以忽略这个泄露。 22 | 如果一定要解决,方法如下: 23 | ~~~cpp 24 | #include 25 | 26 | int main() 27 | { 28 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L 29 | OPENSSL_init_ssl(0, NULL); 30 | #endif 31 | ... 32 | } 33 | ~~~ 34 | 也就是说在使用我们的库之前,先初始化openssl。如果你有需要也可以同时配置openssl的参数。 35 | 注意这个函数只在openssl1.1以上版本才有提供,所以调用之前需要先判断openssl版本。 36 | 这个内存泄露与openssl1.1的内存释放原理有关。我们提供的这个方案可以解决这个问题(但我们还是建议用户忽略)。 37 | -------------------------------------------------------------------------------- /workflow/docs/about-go-task.md: -------------------------------------------------------------------------------- 1 | # 关于go task 2 | 3 | 我们提供了另一种更简单的使用计算任务的方法,模仿go语言实现的go task。 4 | 使用go task来实计算任务无需定义输入与输出,所有数据通过函数参数传递。 5 | 6 | # 创建go task 7 | ~~~cpp 8 | class WFTaskFactory 9 | { 10 | ... 11 | public: 12 | template 13 | static WFGoTask *create_go_task(const std::string& queue_name, 14 | FUNC&& func, ARGS&&... args); 15 | }; 16 | ~~~ 17 | 18 | # 示例 19 | 我们想异步的运行一个加法函数:void add(int a, int b, int& res); 20 | 并且我们还想在函数运行结束的时候打印出结果。于是可以这样实现: 21 | ~~~cpp 22 | #include 23 | #include 24 | #include "workflow/WFTaskFactory.h" 25 | #include "workflow/WFFacilities.h" 26 | 27 | void add(int a, int b, int& res) 28 | { 29 | res = a + b; 30 | } 31 | 32 | int main(void) 33 | { 34 | WFFacilities::WaitGroup wait_group(1); 35 | int a = 1; 36 | int b = 1; 37 | int res; 38 | 39 | WFGoTask *task = WFTaskFactory::create_go_task("test", add, a, b, std::ref(res)); 40 | task->set_callback([&](WFGoTask *task) { 41 | printf("%d + %d = %d\n", a, b, res); 42 | wait_group.done(); 43 | }); 44 | 45 | task->start(); 46 | wait_group.wait(); 47 | return 0; 48 | } 49 | ~~~ 50 | 以上的示例异步运行一个加法,打印结果并退出程序。go task的使用与其它的任务没有多少区别,也有user_data域可以使用。 51 | 唯一一点不同,是go task创建时不传callback,但和其它任务一样可以set_callback。 52 | 如果go task函数的某个参数是引用,需要使用std::ref,否则会变成值传递,这是c++11的特征。 53 | 54 | # 把workflow当成线程池 55 | 56 | 用户可以只使用go task,这样可以将workflow退化成一个线程池,而且线程数量默认等于机器cpu数。 57 | 但是这个线程池比一般的线程池又有更多的功能,比如每个任务有queue name,任务之间还可以组成各种串并联或更复杂的依赖关系。 58 | 59 | -------------------------------------------------------------------------------- /workflow/docs/about-timer.md: -------------------------------------------------------------------------------- 1 | # 关于定时器 2 | 3 | 定时器的作用是不占线程的等待一个确定时间,同样通过callback来通知定时器到期。 4 | 5 | # 定时器的创建 6 | 7 | 同样是在WFTaskFactory类里的方法: 8 | ~~~cpp 9 | using timer_callback_t = std::function; 10 | 11 | class WFTaskFactory 12 | { 13 | ... 14 | static WFTimerTask *create_timer_task(unsigned int microseconds, 15 | timer_callback_t callback); 16 | static WFTimerTask *create_timer_task(time_t seconds, long nanoseconds, 17 | timer_callback_t callback); 18 | }; 19 | ~~~ 20 | 目前我们提供两个创建定时器的工厂函数。第一个函数接收一个unsigned int型参,时间单位为微秒。 21 | 如果用户需要更长时间或更高精度的定时,可以使用第二个函数接口。接口接受两个参数,分别为秒和纳秒。实际上,这个接口也具备更高的性能。 22 | 定时器任务里同样有user_data域可以用来传递一些用户数据。启动方法和接入任务流的方法与其它任务没有区别。 23 | 24 | # 定时器的一个高级特征 25 | 26 | 在[关于程序退出](./about-exit.md)里讲到,main函数结束或exit()被调用的时候,所有任务必须里运行到callback,并且没有新的任务被调起。 27 | 这时就可能出现一个问题,定时器的定时周期可以非常长,并且不能主动打断(打断定时器的功能正在研发)。如果等定时器到期,程序退出需要很长时间。 28 | 而实现上,程序退出是可以打断定时器,让定时器回到callback的。如果定时器被程序退出打断,get_state()会得到一个WFT_STATE_ABORTED状态。 29 | 当然如果定时器被程序退出打断,则不能再调起新的任务。 30 | 以下这个程序,每间隔一秒抓取一个一个http页面。当所有url抓完毕,程序直接退出,不用等待timer回到callback,退出不会有延迟。 31 | ~~~cpp 32 | bool program_terminate = false; 33 | 34 | void timer_callback(WFTimerTask *timer) 35 | { 36 | mutex.lock(); 37 | if (!program_terminate) 38 | { 39 | WFHttpTask *task; 40 | if (urls_to_fetch > 0) 41 | { 42 | task = WFTaskFactory::create_http_task(...); 43 | series_of(timer)->push_back(task); 44 | } 45 | 46 | series_of(timer)->push_back(WFTaskFactory::create_timer_task(1, 0, timer_callback)); 47 | } 48 | mutex.unlock(); 49 | } 50 | 51 | ... 52 | int main() 53 | { 54 | .... 55 | /* all urls done */ 56 | mutex.lock(); 57 | program_terminate = true; 58 | mutex.unlock(); 59 | return 0; 60 | } 61 | ~~~ 62 | 以上程序,timer_callback必须在锁里判断program_terminate条件,否则可能在程序已经结束的情况下又调起新任务。 63 | -------------------------------------------------------------------------------- /workflow/src/algorithm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(algorithm) 3 | 4 | set(SRC 5 | DnsRoutine.cc 6 | ) 7 | 8 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 9 | 10 | -------------------------------------------------------------------------------- /workflow/src/algorithm/MapReduce.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _MAPREDUCE_H_ 20 | #define _MAPREDUCE_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "rbtree.h" 27 | 28 | namespace algorithm 29 | { 30 | 31 | template 32 | class ReduceIterator 33 | { 34 | public: 35 | virtual const VAL *next() = 0; 36 | virtual size_t size() = 0; 37 | 38 | protected: 39 | virtual ~ReduceIterator() { } 40 | }; 41 | 42 | template 43 | using reduce_function_t = 44 | std::function *, VAL *)>; 45 | 46 | template 47 | class Reducer 48 | { 49 | public: 50 | void insert(KEY&& key, VAL&& val); 51 | 52 | public: 53 | void start(reduce_function_t reduce, 54 | std::vector> *output); 55 | 56 | private: 57 | struct rb_root key_tree; 58 | 59 | public: 60 | Reducer() { this->key_tree.rb_node = NULL; } 61 | virtual ~Reducer(); 62 | }; 63 | 64 | } 65 | 66 | #include "MapReduce.inl" 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /workflow/src/client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(client) 3 | 4 | set(SRC 5 | WFDnsClient.cc 6 | ) 7 | 8 | if (NOT MYSQL STREQUAL "n") 9 | set(SRC 10 | ${SRC} 11 | WFMySQLConnection.cc 12 | ) 13 | endif () 14 | 15 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 16 | 17 | if (KAFKA STREQUAL "y") 18 | set(SRC 19 | WFKafkaClient.cc 20 | ) 21 | add_library("client_kafka" OBJECT ${SRC}) 22 | set_property(SOURCE WFKafkaClient.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 23 | endif () 24 | -------------------------------------------------------------------------------- /workflow/src/client/WFDnsClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Liu Kai (liukaidx@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFDNSCLIENT_H_ 20 | #define _WFDNSCLIENT_H_ 21 | 22 | #include 23 | #include 24 | #include "WFTaskFactory.h" 25 | #include "DnsMessage.h" 26 | 27 | class WFDnsClient 28 | { 29 | public: 30 | WFDnsClient() : params(NULL) { } 31 | virtual ~WFDnsClient() { } 32 | 33 | int init(const std::string& url); 34 | int init(const std::string& url, const std::string& search_list, 35 | int ndots, int attempts, bool rotate); 36 | void deinit(); 37 | 38 | WFDnsTask *create_dns_task(const std::string& name, 39 | dns_callback_t callback); 40 | 41 | private: 42 | void *params; 43 | std::atomic id; 44 | }; 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /workflow/src/client/WFMySQLConnection.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "URIParser.h" 24 | #include "WFMySQLConnection.h" 25 | 26 | int WFMySQLConnection::init(const std::string& url) 27 | { 28 | std::string query; 29 | ParsedURI uri; 30 | 31 | if (URIParser::parse(url, uri) >= 0) 32 | { 33 | if (uri.query) 34 | { 35 | query = uri.query; 36 | query += '&'; 37 | } 38 | 39 | query += "transaction=INTERNAL_CONN_ID_" + std::to_string(this->id); 40 | free(uri.query); 41 | uri.query = strdup(query.c_str()); 42 | if (uri.query) 43 | { 44 | this->uri = std::move(uri); 45 | return 0; 46 | } 47 | } 48 | 49 | return -1; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /workflow/src/factory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(factory) 3 | 4 | set(SRC 5 | WFGraphTask.cc 6 | DnsTaskImpl.cc 7 | WFTaskFactory.cc 8 | Workflow.cc 9 | HttpTaskImpl.cc 10 | WFResourcePool.cc 11 | FileTaskImpl.cc 12 | ) 13 | 14 | if (NOT MYSQL STREQUAL "n") 15 | set(SRC 16 | ${SRC} 17 | MySQLTaskImpl.cc 18 | ) 19 | endif () 20 | 21 | if (NOT REDIS STREQUAL "n") 22 | set(SRC 23 | ${SRC} 24 | RedisTaskImpl.cc 25 | ) 26 | endif () 27 | 28 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 29 | 30 | if (KAFKA STREQUAL "y") 31 | set(SRC 32 | KafkaTaskImpl.cc 33 | ) 34 | add_library("factory_kafka" OBJECT ${SRC}) 35 | set_property(SOURCE KafkaTaskImpl.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 36 | endif () 37 | -------------------------------------------------------------------------------- /workflow/src/factory/WFConnection.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFCONNECTION_H_ 20 | #define _WFCONNECTION_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "Communicator.h" 26 | 27 | class WFConnection : public CommConnection 28 | { 29 | public: 30 | void *get_context() const 31 | { 32 | return this->context; 33 | } 34 | 35 | void set_context(void *context, std::function deleter) 36 | { 37 | this->context = context; 38 | this->deleter = std::move(deleter); 39 | } 40 | 41 | void *test_set_context(void *test_context, void *new_context, 42 | std::function deleter) 43 | { 44 | if (this->context.compare_exchange_strong(test_context, new_context)) 45 | { 46 | this->deleter = std::move(deleter); 47 | return new_context; 48 | } 49 | 50 | return test_context; 51 | } 52 | 53 | private: 54 | std::atomic context; 55 | std::function deleter; 56 | 57 | public: 58 | WFConnection() : context(NULL) { } 59 | 60 | protected: 61 | virtual ~WFConnection() 62 | { 63 | if (this->deleter) 64 | this->deleter(this->context); 65 | } 66 | }; 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /workflow/src/factory/WFResourcePool.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Li Yingxin (liyingxin@sogou-inc.com) 17 | Xie Han (xiehan@sogou-inc.com) 18 | */ 19 | 20 | #ifndef _WFRESOURCEPOOL_H_ 21 | #define _WFRESOURCEPOOL_H_ 22 | 23 | #include 24 | #include "list.h" 25 | #include "WFTask.h" 26 | 27 | class WFResourcePool 28 | { 29 | public: 30 | WFConditional *get(SubTask *task, void **resbuf); 31 | void post(void *res); 32 | 33 | public: 34 | struct Data 35 | { 36 | void *pop() { return this->pool->pop(); } 37 | void push(void *res) { this->pool->push(res); } 38 | 39 | void **res; // void* 的数组, 管理资源池中的资源 40 | long value; // 这里是剩余资源的大小 41 | size_t index; 42 | struct list_head wait_list; // 把等待的conditional task串成链表 43 | std::mutex mutex; 44 | WFResourcePool *pool; 45 | }; 46 | 47 | private: 48 | virtual void *pop() 49 | { 50 | LOG_TRACE("WFResourcePool:: pop"); 51 | return this->data.res[this->data.index++]; 52 | } 53 | 54 | virtual void push(void *res) 55 | { 56 | LOG_TRACE("WFResourcePool:: push"); 57 | this->data.res[--this->data.index] = res; 58 | } 59 | 60 | private: 61 | struct Data data; 62 | 63 | private: 64 | void create(size_t n); 65 | 66 | public: 67 | WFResourcePool(void *const *res, size_t n); 68 | WFResourcePool(size_t n); 69 | virtual ~WFResourcePool() { delete []this->data.res; } 70 | }; 71 | 72 | #endif 73 | 74 | -------------------------------------------------------------------------------- /workflow/src/include/workflow/CommRequest.h: -------------------------------------------------------------------------------- 1 | ../../kernel/CommRequest.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/CommScheduler.h: -------------------------------------------------------------------------------- 1 | ../../kernel/CommScheduler.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/Communicator.h: -------------------------------------------------------------------------------- 1 | ../../kernel/Communicator.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/DnsCache.h: -------------------------------------------------------------------------------- 1 | ../../manager/DnsCache.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/DnsMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/DnsMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/DnsRoutine.h: -------------------------------------------------------------------------------- 1 | ../../algorithm/DnsRoutine.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/DnsUtil.h: -------------------------------------------------------------------------------- 1 | ../../protocol/DnsUtil.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/EncodeStream.h: -------------------------------------------------------------------------------- 1 | ../../util/EncodeStream.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/EndpointParams.h: -------------------------------------------------------------------------------- 1 | ../../manager/EndpointParams.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/ExecRequest.h: -------------------------------------------------------------------------------- 1 | ../../kernel/ExecRequest.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/Executor.h: -------------------------------------------------------------------------------- 1 | ../../kernel/Executor.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/HttpMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/HttpMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/HttpUtil.h: -------------------------------------------------------------------------------- 1 | ../../protocol/HttpUtil.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/IORequest.h: -------------------------------------------------------------------------------- 1 | ../../kernel/IORequest.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/IOService_linux.h: -------------------------------------------------------------------------------- 1 | ../../kernel/IOService_linux.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/IOService_thread.h: -------------------------------------------------------------------------------- 1 | ../../kernel/IOService_thread.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/KafkaDataTypes.h: -------------------------------------------------------------------------------- 1 | ../../protocol/KafkaDataTypes.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/KafkaMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/KafkaMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/KafkaResult.h: -------------------------------------------------------------------------------- 1 | ../../protocol/KafkaResult.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/KafkaTaskImpl.inl: -------------------------------------------------------------------------------- 1 | ../../factory/KafkaTaskImpl.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/LRUCache.h: -------------------------------------------------------------------------------- 1 | ../../util/LRUCache.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/MD5Util.h: -------------------------------------------------------------------------------- 1 | ../../util/MD5Util.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/MapReduce.h: -------------------------------------------------------------------------------- 1 | ../../algorithm/MapReduce.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/MapReduce.inl: -------------------------------------------------------------------------------- 1 | ../../algorithm/MapReduce.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/MySQLMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/MySQLMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/MySQLMessage.inl: -------------------------------------------------------------------------------- 1 | ../../protocol/MySQLMessage.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/MySQLResult.h: -------------------------------------------------------------------------------- 1 | ../../protocol/MySQLResult.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/MySQLResult.inl: -------------------------------------------------------------------------------- 1 | ../../protocol/MySQLResult.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/ProtocolMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/ProtocolMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/RedisMessage.h: -------------------------------------------------------------------------------- 1 | ../../protocol/RedisMessage.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/RouteManager.h: -------------------------------------------------------------------------------- 1 | ../../manager/RouteManager.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/SSLWrapper.h: -------------------------------------------------------------------------------- 1 | ../../protocol/SSLWrapper.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/SleepRequest.h: -------------------------------------------------------------------------------- 1 | ../../kernel/SleepRequest.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/StringUtil.h: -------------------------------------------------------------------------------- 1 | ../../util/StringUtil.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/SubTask.h: -------------------------------------------------------------------------------- 1 | ../../kernel/SubTask.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/URIParser.h: -------------------------------------------------------------------------------- 1 | ../../util/URIParser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/UpstreamManager.h: -------------------------------------------------------------------------------- 1 | ../../manager/UpstreamManager.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/UpstreamPolicies.h: -------------------------------------------------------------------------------- 1 | ../../nameservice/UpstreamPolicies.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFAlgoTaskFactory.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFAlgoTaskFactory.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFAlgoTaskFactory.inl: -------------------------------------------------------------------------------- 1 | ../../factory/WFAlgoTaskFactory.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFConnection.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFConnection.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFDnsClient.h: -------------------------------------------------------------------------------- 1 | ../../client/WFDnsClient.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFDnsResolver.h: -------------------------------------------------------------------------------- 1 | ../../nameservice/WFDnsResolver.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFDnsServer.h: -------------------------------------------------------------------------------- 1 | ../../server/WFDnsServer.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFFacilities.h: -------------------------------------------------------------------------------- 1 | ../../manager/WFFacilities.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFFacilities.inl: -------------------------------------------------------------------------------- 1 | ../../manager/WFFacilities.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFFuture.h: -------------------------------------------------------------------------------- 1 | ../../manager/WFFuture.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFGlobal.h: -------------------------------------------------------------------------------- 1 | ../../manager/WFGlobal.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFGraphTask.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFGraphTask.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFHttpServer.h: -------------------------------------------------------------------------------- 1 | ../../server/WFHttpServer.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFKafkaClient.h: -------------------------------------------------------------------------------- 1 | ../../client/WFKafkaClient.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFMySQLConnection.h: -------------------------------------------------------------------------------- 1 | ../../client/WFMySQLConnection.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFMySQLServer.h: -------------------------------------------------------------------------------- 1 | ../../server/WFMySQLServer.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFNameService.h: -------------------------------------------------------------------------------- 1 | ../../nameservice/WFNameService.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFOperator.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFOperator.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFRedisServer.h: -------------------------------------------------------------------------------- 1 | ../../server/WFRedisServer.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFResourcePool.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFResourcePool.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFServer.h: -------------------------------------------------------------------------------- 1 | ../../server/WFServer.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFServiceGovernance.h: -------------------------------------------------------------------------------- 1 | ../../nameservice/WFServiceGovernance.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFTask.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFTask.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFTask.inl: -------------------------------------------------------------------------------- 1 | ../../factory/WFTask.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFTaskError.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFTaskError.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFTaskFactory.h: -------------------------------------------------------------------------------- 1 | ../../factory/WFTaskFactory.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/WFTaskFactory.inl: -------------------------------------------------------------------------------- 1 | ../../factory/WFTaskFactory.inl -------------------------------------------------------------------------------- /workflow/src/include/workflow/Workflow.h: -------------------------------------------------------------------------------- 1 | ../../factory/Workflow.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/crc32c.h: -------------------------------------------------------------------------------- 1 | ../../util/crc32c.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/dns_parser.h: -------------------------------------------------------------------------------- 1 | ../../protocol/dns_parser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/http_parser.h: -------------------------------------------------------------------------------- 1 | ../../protocol/http_parser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/kafka_parser.h: -------------------------------------------------------------------------------- 1 | ../../protocol/kafka_parser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/list.h: -------------------------------------------------------------------------------- 1 | ../../kernel/list.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/mpoller.h: -------------------------------------------------------------------------------- 1 | ../../kernel/mpoller.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/msgqueue.h: -------------------------------------------------------------------------------- 1 | ../../kernel/msgqueue.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/mysql_byteorder.h: -------------------------------------------------------------------------------- 1 | ../../protocol/mysql_byteorder.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/mysql_parser.h: -------------------------------------------------------------------------------- 1 | ../../protocol/mysql_parser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/mysql_stream.h: -------------------------------------------------------------------------------- 1 | ../../protocol/mysql_stream.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/mysql_types.h: -------------------------------------------------------------------------------- 1 | ../../protocol/mysql_types.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/poller.h: -------------------------------------------------------------------------------- 1 | ../../kernel/poller.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/rbtree.h: -------------------------------------------------------------------------------- 1 | ../../kernel/rbtree.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/redis_parser.h: -------------------------------------------------------------------------------- 1 | ../../protocol/redis_parser.h -------------------------------------------------------------------------------- /workflow/src/include/workflow/thrdpool.h: -------------------------------------------------------------------------------- 1 | ../../kernel/thrdpool.h -------------------------------------------------------------------------------- /workflow/src/kernel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(kernel) 3 | 4 | if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") 5 | set(IOSERVICE_FILE IOService_linux.cc) 6 | elseif (UNIX) 7 | set(IOSERVICE_FILE IOService_thread.cc) 8 | else () 9 | message(FATAL_ERROR "IOService unsupported.") 10 | endif () 11 | 12 | set(SRC 13 | ${IOSERVICE_FILE} 14 | logger.c 15 | mpoller.c 16 | poller.c 17 | rbtree.c 18 | msgqueue.c 19 | thrdpool.c 20 | CommRequest.cc 21 | CommScheduler.cc 22 | Communicator.cc 23 | Executor.cc 24 | SubTask.cc 25 | ) 26 | 27 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 28 | 29 | -------------------------------------------------------------------------------- /workflow/src/kernel/CommRequest.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #include 20 | #include "CommScheduler.h" 21 | #include "CommRequest.h" 22 | 23 | void CommRequest::handle(int state, int error) 24 | { 25 | LOG_TRACE("CommRequest::handle"); 26 | this->state = state; 27 | this->error = error; 28 | if (error != ETIMEDOUT) 29 | this->timeout_reason = TOR_NOT_TIMEOUT; 30 | else if (!this->get_message_out()) 31 | this->timeout_reason = TOR_CONNECT_TIMEOUT; 32 | else 33 | this->timeout_reason = TOR_TRANSMIT_TIMEOUT; 34 | 35 | this->subtask_done(); 36 | } 37 | 38 | void CommRequest::dispatch() 39 | { 40 | LOG_TRACE("CommRequest::dispatch"); 41 | // 发送请求 42 | if (this->scheduler->request(this, this->object, this->wait_timeout, 43 | &this->target) < 0) 44 | { 45 | this->state = CS_STATE_ERROR; 46 | this->error = errno; 47 | if (errno != ETIMEDOUT) 48 | this->timeout_reason = TOR_NOT_TIMEOUT; 49 | else 50 | this->timeout_reason = TOR_WAIT_TIMEOUT; 51 | 52 | this->subtask_done(); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /workflow/src/kernel/ExecRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _EXECREQUEST_H_ 20 | #define _EXECREQUEST_H_ 21 | 22 | #include "SubTask.h" 23 | #include "Executor.h" 24 | #include "logger.h" 25 | 26 | class ExecRequest : public SubTask, public ExecSession 27 | { 28 | public: 29 | ExecRequest(ExecQueue *queue, Executor *executor) 30 | { 31 | LOG_TRACE("ExecRequest creator"); 32 | this->executor = executor; 33 | this->queue = queue; 34 | } 35 | 36 | ExecQueue *get_request_queue() const { return this->queue; } 37 | void set_request_queue(ExecQueue *queue) { this->queue = queue; } 38 | 39 | public: 40 | virtual void dispatch() 41 | { 42 | LOG_TRACE("ExecRequest dispatch"); 43 | if (this->executor->request(this, this->queue) < 0) 44 | { 45 | this->state = ES_STATE_ERROR; 46 | this->error = errno; 47 | this->subtask_done(); 48 | } 49 | } 50 | 51 | protected: 52 | int state; 53 | int error; 54 | 55 | protected: 56 | ExecQueue *queue; 57 | Executor *executor; 58 | 59 | protected: 60 | virtual void handle(int state, int error) 61 | { 62 | LOG_TRACE("ExecRequest handle"); 63 | this->state = state; 64 | this->error = error; 65 | this->subtask_done(); 66 | } 67 | }; 68 | 69 | #endif 70 | 71 | -------------------------------------------------------------------------------- /workflow/src/kernel/IORequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _IOREQUEST_H_ 20 | #define _IOREQUEST_H_ 21 | 22 | #include "SubTask.h" 23 | #include "Communicator.h" 24 | 25 | class IORequest : public SubTask, public IOSession 26 | { 27 | public: 28 | IORequest(IOService *service) 29 | { 30 | this->service = service; 31 | } 32 | 33 | public: 34 | virtual void dispatch() 35 | { 36 | if (this->service->request(this) < 0) 37 | { 38 | this->state = IOS_STATE_ERROR; 39 | this->error = errno; 40 | this->subtask_done(); 41 | } 42 | } 43 | 44 | protected: 45 | int state; 46 | int error; 47 | 48 | protected: 49 | IOService *service; 50 | 51 | protected: 52 | virtual void handle(int state, int error) 53 | { 54 | this->state = state; 55 | this->error = error; 56 | this->subtask_done(); 57 | } 58 | }; 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /workflow/src/kernel/SleepRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _SLEEPREQUEST_H_ 20 | #define _SLEEPREQUEST_H_ 21 | 22 | #include "SubTask.h" 23 | #include "Communicator.h" 24 | #include "CommScheduler.h" 25 | 26 | class SleepRequest : public SubTask, public SleepSession 27 | { 28 | public: 29 | SleepRequest(CommScheduler *scheduler) 30 | { 31 | LOG_TRACE("SleepRequest creator"); 32 | this->scheduler = scheduler; 33 | } 34 | 35 | public: 36 | virtual void dispatch() 37 | { 38 | LOG_TRACE("SleepRequest dispatch"); 39 | if (this->scheduler->sleep(this) < 0) 40 | { 41 | this->state = SS_STATE_ERROR; 42 | this->error = errno; 43 | this->subtask_done(); 44 | } 45 | } 46 | 47 | protected: 48 | int state; 49 | int error; 50 | 51 | protected: 52 | CommScheduler *scheduler; 53 | 54 | protected: 55 | virtual void handle(int state, int error) 56 | { 57 | LOG_TRACE("SleepRequest handle"); 58 | this->state = state; 59 | this->error = error; 60 | this->subtask_done(); 61 | } 62 | }; 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /workflow/src/kernel/msgqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _MSGQUEUE_H_ 20 | #define _MSGQUEUE_H_ 21 | 22 | #include 23 | 24 | typedef struct __msgqueue msgqueue_t; 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* A simple implementation of message queue. The max pending messages may 32 | * reach two times 'maxlen' when the queue is in blocking mode, and infinite 33 | * in nonblocking mode. 'linkoff' is the offset from the head of each message, 34 | * where spaces of one pointer size should be available for internal usage. 35 | * 'linkoff' can be positive or negative or zero. */ 36 | 37 | msgqueue_t *msgqueue_create(size_t maxlen, int linkoff); 38 | void msgqueue_put(void *msg, msgqueue_t *queue); 39 | void *msgqueue_get(msgqueue_t *queue); 40 | void msgqueue_set_nonblock(msgqueue_t *queue); 41 | void msgqueue_set_block(msgqueue_t *queue); 42 | void msgqueue_destroy(msgqueue_t *queue); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /workflow/src/kernel/thrdpool.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _THRDPOOL_H_ 20 | #define _THRDPOOL_H_ 21 | 22 | #include 23 | 24 | typedef struct __thrdpool thrdpool_t; 25 | 26 | struct thrdpool_task 27 | { 28 | void (*routine)(void *); 29 | void *context; 30 | }; 31 | 32 | #ifdef __cplusplus 33 | extern "C" 34 | { 35 | #endif 36 | 37 | /* 38 | * Thread pool originates from project Sogou C++ Workflow 39 | * https://github.com/sogou/workflow 40 | * 41 | * A thread task can be scheduled by another task, which is very important, 42 | * even if the pool is being destroyed. Because thread task is hard to know 43 | * what's happening to the pool. 44 | * The thread pool can also be destroyed by a thread task. This may sound 45 | * strange, but it's very logical. Destroying thread pool in thread task 46 | * does not end the task thread. It'll run till the end of task. 47 | */ 48 | 49 | thrdpool_t *thrdpool_create(size_t nthreads, size_t stacksize); 50 | int thrdpool_schedule(const struct thrdpool_task *task, thrdpool_t *pool); 51 | int thrdpool_increase(thrdpool_t *pool); 52 | int thrdpool_in_pool(thrdpool_t *pool); 53 | void thrdpool_destroy(void (*pending)(const struct thrdpool_task *), 54 | thrdpool_t *pool); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /workflow/src/manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(manager) 3 | 4 | set(SRC 5 | DnsCache.cc 6 | RouteManager.cc 7 | WFGlobal.cc 8 | ) 9 | 10 | if (NOT UPSTREAM STREQUAL "n") 11 | set(SRC 12 | ${SRC} 13 | UpstreamManager.cc 14 | ) 15 | endif () 16 | 17 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 18 | -------------------------------------------------------------------------------- /workflow/src/manager/EndpointParams.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wu Jiaxu (wujiaxu@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _ENDPOINTPARAMS_H_ 20 | #define _ENDPOINTPARAMS_H_ 21 | 22 | #include 23 | 24 | /** 25 | * @file EndpointParams.h 26 | * @brief Network config for client task 27 | */ 28 | 29 | enum TransportType 30 | { 31 | TT_TCP, 32 | TT_UDP, 33 | TT_SCTP, 34 | TT_TCP_SSL, 35 | TT_SCTP_SSL, 36 | }; 37 | 38 | struct EndpointParams 39 | { 40 | size_t max_connections; 41 | int connect_timeout; 42 | int response_timeout; 43 | int ssl_connect_timeout; 44 | bool use_tls_sni; 45 | }; 46 | 47 | static constexpr struct EndpointParams ENDPOINT_PARAMS_DEFAULT = 48 | { 49 | .max_connections = 200, 50 | .connect_timeout = 10 * 1000, 51 | .response_timeout = 10 * 1000, 52 | .ssl_connect_timeout = 10 * 1000, 53 | .use_tls_sni = false, 54 | }; 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /workflow/src/nameservice/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(nameservice) 3 | 4 | set(SRC 5 | WFNameService.cc 6 | WFDnsResolver.cc 7 | ) 8 | 9 | if (NOT UPSTREAM STREQUAL "n") 10 | set(SRC 11 | ${SRC} 12 | WFServiceGovernance.cc 13 | UpstreamPolicies.cc 14 | ) 15 | endif () 16 | 17 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 18 | -------------------------------------------------------------------------------- /workflow/src/nameservice/WFDnsResolver.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFDNSRESOLVER_H_ 20 | #define _WFDNSRESOLVER_H_ 21 | 22 | #include "EndpointParams.h" 23 | #include "WFNameService.h" 24 | #include "WFResourcePool.h" 25 | 26 | class WFDnsResolver : public WFNSPolicy 27 | { 28 | public: 29 | virtual WFRouterTask *create_router_task(const struct WFNSParams *params, 30 | router_callback_t callback); 31 | 32 | public: 33 | WFRouterTask *create(const struct WFNSParams *params, int dns_cache_level, 34 | unsigned int dns_ttl_default, unsigned int dns_ttl_min, 35 | const struct EndpointParams *endpoint_params, 36 | router_callback_t&& callback); 37 | 38 | private: 39 | WFResourcePool respool; // 这里资源池用来限制并发度 40 | 41 | private: 42 | WFConditional *get_cond(SubTask *task) 43 | { 44 | static void *buf; 45 | return this->respool.get(task, &buf); 46 | } 47 | 48 | void post_cond() { this->respool.post(NULL); } 49 | 50 | public: 51 | WFDnsResolver(); 52 | friend class WFResolverTask; 53 | }; 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /workflow/src/protocol/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(protocol) 3 | 4 | set(SRC 5 | dns_parser.c 6 | DnsMessage.cc 7 | DnsUtil.cc 8 | SSLWrapper.cc 9 | http_parser.c 10 | HttpMessage.cc 11 | HttpUtil.cc 12 | ) 13 | 14 | if (NOT MYSQL STREQUAL "n") 15 | set(SRC 16 | ${SRC} 17 | mysql_stream.c 18 | mysql_parser.c 19 | mysql_byteorder.c 20 | MySQLMessage.cc 21 | MySQLResult.cc 22 | ) 23 | endif () 24 | 25 | if (NOT REDIS STREQUAL "n") 26 | set(SRC 27 | ${SRC} 28 | redis_parser.c 29 | RedisMessage.cc 30 | ) 31 | endif () 32 | 33 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 34 | 35 | if (KAFKA STREQUAL "y") 36 | set(SRC 37 | kafka_parser.c 38 | KafkaMessage.cc 39 | KafkaDataTypes.cc 40 | KafkaResult.cc 41 | ) 42 | add_library("protocol_kafka" OBJECT ${SRC}) 43 | set_property(SOURCE KafkaMessage.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 44 | set_property(SOURCE KafkaDataTypes.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 45 | set_property(SOURCE KafkaResult.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 46 | endif () 47 | -------------------------------------------------------------------------------- /workflow/src/protocol/KafkaResult.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wang Zhulei (wangzhulei@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _KAFKARESULT_H_ 20 | #define _KAFKARESULT_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "KafkaMessage.h" 26 | #include "KafkaDataTypes.h" 27 | 28 | namespace protocol 29 | { 30 | 31 | class KafkaResult 32 | { 33 | public: 34 | // for offsetcommit 35 | void fetch_toppars(std::vector& toppars); 36 | 37 | // for produce, fetch 38 | void fetch_records(std::vector>& records); 39 | 40 | public: 41 | void create(size_t n); 42 | 43 | void set_resp(KafkaResponse&& resp, size_t i); 44 | 45 | public: 46 | KafkaResult(); 47 | 48 | virtual ~KafkaResult() 49 | { 50 | delete []this->resp_vec; 51 | } 52 | 53 | KafkaResult& operator= (KafkaResult&& move); 54 | 55 | KafkaResult(KafkaResult&& move); 56 | 57 | private: 58 | KafkaResponse *resp_vec; 59 | size_t resp_num; 60 | }; 61 | 62 | } 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /workflow/src/protocol/mysql_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _MYSQL_STREAM_H_ 20 | #define _MYSQL_STREAM_H_ 21 | 22 | #include 23 | 24 | typedef struct __mysql_stream 25 | { 26 | unsigned char head[4]; 27 | unsigned char head_left; 28 | unsigned char sequence_id; 29 | int payload_length; 30 | int payload_left; 31 | void *buf; 32 | size_t length; 33 | size_t bufsize; 34 | int (*write)(const void *, size_t *, struct __mysql_stream *); 35 | } mysql_stream_t; 36 | 37 | #ifdef __cplusplus 38 | extern "C" 39 | { 40 | #endif 41 | 42 | void mysql_stream_init(mysql_stream_t *stream); 43 | int mysql_stream_write(const void *buf, size_t n, mysql_stream_t *stream); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | static inline int mysql_stream_get_seq(mysql_stream_t *stream) 50 | { 51 | return stream->sequence_id; 52 | } 53 | 54 | static inline void mysql_stream_get_buf(const void **buf, size_t *length, 55 | mysql_stream_t *stream) 56 | { 57 | *buf = stream->buf; 58 | *length = stream->length; 59 | } 60 | 61 | static inline void mysql_stream_deinit(mysql_stream_t *stream) 62 | { 63 | free(stream->buf); 64 | } 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /workflow/src/server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(server) 3 | 4 | set(SRC 5 | WFServer.cc 6 | ) 7 | 8 | if (NOT MYSQL STREQUAL "n") 9 | set(SRC 10 | ${SRC} 11 | WFMySQLServer.cc 12 | ) 13 | endif () 14 | 15 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 16 | -------------------------------------------------------------------------------- /workflow/src/server/WFDnsServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Liu Kai (liukaidx@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFDNSSERVER_H_ 20 | #define _WFDNSSERVER_H_ 21 | 22 | #include "DnsMessage.h" 23 | #include "WFServer.h" 24 | #include "WFTaskFactory.h" 25 | 26 | using dns_process_t = std::function; 27 | using WFDnsServer = WFServer; 29 | 30 | static constexpr struct WFServerParams DNS_SERVER_PARAMS_DEFAULT = 31 | { 32 | .max_connections = 2000, 33 | .peer_response_timeout = 10 * 1000, 34 | .receive_timeout = -1, 35 | .keep_alive_timeout = 300 * 1000, 36 | .request_size_limit = (size_t)-1, 37 | .ssl_accept_timeout = 5000, 38 | }; 39 | 40 | template<> 41 | inline WFDnsServer::WFServer(dns_process_t proc) : 42 | WFServerBase(&DNS_SERVER_PARAMS_DEFAULT), 43 | process(std::move(proc)) 44 | { 45 | } 46 | 47 | #endif 48 | 49 | -------------------------------------------------------------------------------- /workflow/src/server/WFMySQLServer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wu Jiaxu (wujiaxu@sogou-inc.com) 17 | */ 18 | 19 | #include "WFMySQLServer.h" 20 | 21 | WFConnection *WFMySQLServer::new_connection(int accept_fd) 22 | { 23 | WFConnection *conn = this->WFServer::new_connection(accept_fd); 24 | 25 | if (conn) 26 | { 27 | protocol::MySQLHandshakeResponse resp; 28 | struct iovec vec[8]; 29 | int count; 30 | 31 | resp.server_set(0x0a, "5.5", 1, (const uint8_t *)"12345678", 32 | 0, 33, 0, (const uint8_t *)"123456789abc"); 33 | count = resp.encode(vec, 8); 34 | if (count >= 0) 35 | { 36 | if (writev(accept_fd, vec, count) >= 0) 37 | return conn; 38 | } 39 | 40 | this->delete_connection(conn); 41 | } 42 | 43 | return NULL; 44 | } 45 | 46 | CommSession *WFMySQLServer::new_session(long long seq, CommConnection *conn) 47 | { 48 | static mysql_process_t empty = [](WFMySQLTask *){ }; 49 | WFMySQLTask *task; 50 | 51 | task = WFServerTaskFactory::create_mysql_task(this, seq ? this->process : 52 | empty); 53 | task->set_keep_alive(this->params.keep_alive_timeout); 54 | task->set_receive_timeout(this->params.receive_timeout); 55 | task->get_req()->set_size_limit(this->params.request_size_limit); 56 | 57 | return task; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /workflow/src/server/WFMySQLServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wu Jiaxu (wujiaxu@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFMYSQLSERVER_H_ 20 | #define _WFMYSQLSERVER_H_ 21 | 22 | #include 23 | #include "MySQLMessage.h" 24 | #include "WFServer.h" 25 | #include "WFTaskFactory.h" 26 | #include "WFConnection.h" 27 | 28 | using mysql_process_t = std::function; 29 | class MySQLServer; 30 | 31 | static constexpr struct WFServerParams MYSQL_SERVER_PARAMS_DEFAULT = 32 | { 33 | .max_connections = 2000, 34 | .peer_response_timeout = 10 * 1000, 35 | .receive_timeout = -1, 36 | .keep_alive_timeout = 28800 * 1000, 37 | .request_size_limit = (size_t)-1, 38 | .ssl_accept_timeout = 10 * 1000, 39 | }; 40 | 41 | class WFMySQLServer : public WFServer 43 | { 44 | public: 45 | WFMySQLServer(mysql_process_t proc): 46 | WFServer(&MYSQL_SERVER_PARAMS_DEFAULT, std::move(proc)) 47 | { 48 | } 49 | 50 | protected: 51 | virtual WFConnection *new_connection(int accept_fd); 52 | virtual CommSession *new_session(long long seq, CommConnection *conn); 53 | }; 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /workflow/src/server/WFRedisServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Xie Han (xiehan@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _WFREDISSERVER_H_ 20 | #define _WFREDISSERVER_H_ 21 | 22 | #include "RedisMessage.h" 23 | #include "WFServer.h" 24 | #include "WFTaskFactory.h" 25 | 26 | using redis_process_t = std::function; 27 | using WFRedisServer = WFServer; 29 | 30 | static constexpr struct WFServerParams REDIS_SERVER_PARAMS_DEFAULT = 31 | { 32 | .max_connections = 2000, 33 | .peer_response_timeout = 10 * 1000, 34 | .receive_timeout = -1, 35 | .keep_alive_timeout = 300 * 1000, 36 | .request_size_limit = (size_t)-1, 37 | .ssl_accept_timeout = 5000, 38 | }; 39 | 40 | template<> 41 | inline WFRedisServer::WFServer(redis_process_t proc) : 42 | WFServerBase(&REDIS_SERVER_PARAMS_DEFAULT), 43 | process(std::move(proc)) 44 | { 45 | } 46 | 47 | #endif 48 | 49 | -------------------------------------------------------------------------------- /workflow/src/util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(util) 3 | 4 | set(SRC 5 | EncodeStream.cc 6 | StringUtil.cc 7 | URIParser.cc 8 | MD5Util.cc 9 | ) 10 | 11 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 12 | 13 | if (KAFKA STREQUAL "y") 14 | set(SRC 15 | crc32c.c 16 | ) 17 | add_library("util_kafka" OBJECT ${SRC}) 18 | endif () 19 | -------------------------------------------------------------------------------- /workflow/src/util/MD5Util.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wu Jiaxu (wujiaxu@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _MD5UTIL_H_ 20 | #define _MD5UTIL_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | /** 27 | * @file MD5Util.h 28 | * @brief MD5 toolbox 29 | */ 30 | 31 | // static class 32 | class MD5Util 33 | { 34 | public: 35 | //128 bit binary data 36 | static std::string md5_bin(const std::string& str); 37 | //128 bit hex string style, lower case 38 | static std::string md5_string_32(const std::string& str); 39 | //64 bit hex string style, lower case 40 | static std::string md5_string_16(const std::string& str); 41 | 42 | //128 bit integer style 43 | static std::pair md5_integer_32(const std::string& str); 44 | //64 bit integer style 45 | static uint64_t md5_integer_16(const std::string& str); 46 | }; 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /workflow/src/util/StringUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Authors: Wu Jiaxu (wujiaxu@sogou-inc.com) 17 | */ 18 | 19 | #ifndef _STRINGUTIL_H_ 20 | #define _STRINGUTIL_H_ 21 | #include 22 | #include 23 | 24 | /** 25 | * @file StringUtil.h 26 | * @brief String toolbox 27 | */ 28 | 29 | // static class 30 | class StringUtil 31 | { 32 | public: 33 | static size_t url_decode(char *str, size_t len); 34 | static void url_decode(std::string& str); 35 | static std::string url_encode(const std::string& str); 36 | static std::string url_encode_component(const std::string& str); 37 | static std::vector split(const std::string& str, char sep); 38 | static std::string strip(const std::string& str); 39 | static bool start_with(const std::string& str, const std::string& prefix); 40 | 41 | //this will filter any empty result, so the result vector has no empty string 42 | static std::vector split_filter_empty(const std::string& str, char sep); 43 | }; 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /workflow/src/util/crc32c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Magnus Edenhill 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _CRC32C_H_ 28 | #define _CRC32C_H_ 29 | 30 | #include 31 | #include 32 | 33 | #ifdef __cplusplus 34 | extern "C" 35 | { 36 | #endif 37 | 38 | uint32_t crc32c(uint32_t crc, const void *buf, size_t len); 39 | 40 | void crc32c_global_init (void); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif /* _CRC32C_H_ */ 47 | -------------------------------------------------------------------------------- /workflow/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "build type") 4 | 5 | project(workflow_test 6 | LANGUAGES C CXX 7 | ) 8 | 9 | find_library(LIBRT rt) 10 | find_package(OpenSSL REQUIRED) 11 | find_package(workflow REQUIRED CONFIG HINTS ..) 12 | include_directories(${OPENSSL_INCLUDE_DIR} ${WORKFLOW_INCLUDE_DIR}) 13 | link_directories(${WORKFLOW_LIB_DIR}) 14 | 15 | find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) 16 | set(memcheck_command ${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full) 17 | 18 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) 19 | 20 | enable_testing() 21 | find_package(GTest REQUIRED) 22 | 23 | if (WIN32) 24 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP /wd4200") 25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4200 /std:c++14") 26 | else () 27 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIC -pipe -std=gnu90") 28 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fPIC -pipe -std=c++11 -fno-exceptions") 29 | endif () 30 | 31 | set(TEST_LIST 32 | task_unittest 33 | algo_unittest 34 | http_unittest 35 | redis_unittest 36 | mysql_unittest 37 | facilities_unittest 38 | graph_unittest 39 | memory_unittest 40 | upstream_unittest 41 | dns_unittest 42 | resource_unittest 43 | ) 44 | 45 | if (APPLE) 46 | set(WORKFLOW_LIB workflow pthread OpenSSL::SSL OpenSSL::Crypto) 47 | else () 48 | set(WORKFLOW_LIB workflow ${LIBRT}) 49 | endif () 50 | 51 | foreach(src ${TEST_LIST}) 52 | add_executable(${src} EXCLUDE_FROM_ALL ${src}.cc) 53 | target_link_libraries(${src} ${WORKFLOW_LIB} GTest::GTest GTest::Main) 54 | add_test(${src} ${src}) 55 | add_dependencies(check ${src}) 56 | endforeach() 57 | 58 | foreach(src ${TEST_LIST}) 59 | add_test(${src}-memory-check ${memcheck_command} ./${src}) 60 | endforeach() 61 | 62 | -------------------------------------------------------------------------------- /workflow/test/resource_unittest.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Li Yingxin (liyingxin@sogou-inc.com) 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "workflow/WFTask.h" 24 | #include "workflow/WFTaskFactory.h" 25 | #include "workflow/WFResourcePool.h" 26 | #include "workflow/WFFacilities.h" 27 | 28 | TEST(resource_unittest, resource_pool) 29 | { 30 | int res_concurrency = 3; 31 | int task_concurrency = 10; 32 | const char *words[3] = {"workflow", "srpc", "pyworkflow"}; 33 | WFResourcePool res_pool((void * const*)words, res_concurrency); 34 | WFFacilities::WaitGroup wg(task_concurrency); 35 | 36 | for (int i = 0; i < task_concurrency; i++) 37 | { 38 | auto *user_task = WFTaskFactory::create_timer_task(0, 39 | [&wg, &res_pool](WFTimerTask *task) { 40 | uint64_t id = (uint64_t)series_of(task)->get_context(); 41 | printf("task-%lu get [%s]\n", id, (char *)task->user_data); 42 | res_pool.post(task->user_data); 43 | wg.done(); 44 | }); 45 | 46 | auto *cond = res_pool.get(user_task, &user_task->user_data); 47 | 48 | SeriesWork *series = Workflow::create_series_work(cond, nullptr); 49 | series->set_context(reinterpret_cast(i)); 50 | series->start(); 51 | } 52 | 53 | wg.wait(); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /workflow/tutorial/tutorial-00-helloworld.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "workflow/WFHttpServer.h" 3 | 4 | int main() 5 | { 6 | WFHttpServer server([](WFHttpTask *task) { 7 | task->get_resp()->append_output_body("Hello World!"); 8 | }); 9 | 10 | if (server.start(8888) == 0) { // start server on port 8888 11 | getchar(); // press "Enter" to end. 12 | server.stop(); 13 | } 14 | 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /workflow/tutorial/tutorial-10-user_defined_protocol/message.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | Author: Xie Han (xiehan@sogou-inc.com;63350856@qq.com) 17 | */ 18 | 19 | #ifndef _TUTORIALMESSAGE_H_ 20 | #define _TUTORIALMESSAGE_H_ 21 | 22 | #include 23 | #include "workflow/ProtocolMessage.h" 24 | 25 | namespace protocol 26 | { 27 | 28 | class TutorialMessage : public ProtocolMessage 29 | { 30 | private: 31 | virtual int encode(struct iovec vectors[], int max); 32 | virtual int append(const void *buf, size_t size); 33 | 34 | public: 35 | int set_message_body(const void *body, size_t size); 36 | 37 | void get_message_body_nocopy(void **body, size_t *size) 38 | { 39 | *body = this->body; 40 | *size = this->body_size; 41 | } 42 | 43 | protected: 44 | char head[4]; 45 | size_t head_received; 46 | char *body; 47 | size_t body_received; 48 | size_t body_size; 49 | 50 | public: 51 | TutorialMessage() 52 | { 53 | this->head_received = 0; 54 | this->body = NULL; 55 | this->body_size = 0; 56 | } 57 | 58 | TutorialMessage(TutorialMessage&& msg); 59 | TutorialMessage& operator = (TutorialMessage&& msg); 60 | 61 | virtual ~TutorialMessage() 62 | { 63 | free(this->body); 64 | } 65 | }; 66 | 67 | using TutorialRequest = TutorialMessage; 68 | using TutorialResponse = TutorialMessage; 69 | 70 | } 71 | 72 | #endif 73 | 74 | -------------------------------------------------------------------------------- /workflow/workflow-config.cmake: -------------------------------------------------------------------------------- 1 | 2 | ####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### 3 | ####### Any changes to this file will be overwritten by the next CMake run #### 4 | ####### The input file was workflow-config.cmake.in ######## 5 | 6 | get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) 7 | 8 | macro(set_and_check _var _file) 9 | set(${_var} "${_file}") 10 | if(NOT EXISTS "${_file}") 11 | message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") 12 | endif() 13 | endmacro() 14 | 15 | macro(check_required_components _NAME) 16 | foreach(comp ${${_NAME}_FIND_COMPONENTS}) 17 | if(NOT ${_NAME}_${comp}_FOUND) 18 | if(${_NAME}_FIND_REQUIRED_${comp}) 19 | set(${_NAME}_FOUND FALSE) 20 | endif() 21 | endif() 22 | endforeach() 23 | endmacro() 24 | 25 | #################################################################################### 26 | 27 | set(WORKFLOW_VERSION "0.9.7") 28 | set_and_check(WORKFLOW_INCLUDE_DIR "/home/ysy/workflow_annotation/workflow/_include") 29 | set_and_check(WORKFLOW_LIB_DIR "/home/ysy/workflow_annotation/workflow/_lib") 30 | 31 | if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 32 | include ("${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 33 | endif () 34 | 35 | check_required_components(workflow) 36 | -------------------------------------------------------------------------------- /workflow/workflow-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(WORKFLOW_VERSION "@workflow_VERSION@") 4 | set_and_check(WORKFLOW_INCLUDE_DIR "@PACKAGE_CONFIG_INC_DIR@") 5 | set_and_check(WORKFLOW_LIB_DIR "@PACKAGE_CONFIG_LIB_DIR@") 6 | 7 | if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 8 | include ("${CMAKE_CURRENT_LIST_DIR}/workflow-targets.cmake") 9 | endif () 10 | 11 | check_required_components(workflow) 12 | --------------------------------------------------------------------------------