├── .gitignore ├── 01-first-go-program ├── README.md ├── feeds.go ├── go.mod ├── main.go └── searcher │ ├── rss.go │ └── search.go ├── 03-unit-testing ├── mock │ ├── db.go │ ├── go.mod │ ├── go.sum │ ├── mock_db_test.go │ ├── models.go │ ├── store.go │ └── store_test.go ├── mock_faker │ ├── db.go │ ├── go.mod │ ├── go.sum │ ├── mock_db_test.go │ ├── models.go │ ├── store.go │ └── store_test.go ├── mock_suite │ ├── db.go │ ├── go.mod │ ├── go.sum │ ├── mock_db_test.go │ ├── models.go │ ├── store.go │ └── store_test.go └── time │ ├── clock_test.go │ ├── go.mod │ ├── go.sum │ └── timex_test.go ├── 04-simple-data-types ├── example │ └── example.go ├── go.mod ├── go.sum ├── main.go └── runes │ └── runes.go ├── 05-structures ├── child │ └── main.go ├── country │ └── main.go ├── go.mod ├── main.go ├── market │ └── market.go ├── pets │ └── pets.go ├── stack │ └── main.go └── user.go ├── 05-testing ├── asserts_test.go ├── err_and_fatal_test.go ├── golden_files │ ├── golden_test.go │ └── testdata │ │ ├── Aunt Mildred.golden │ │ ├── Cousin Rodney.golden │ │ └── Uncle John.golden ├── titlecase_test.go └── utils.go ├── 08-errors-handling ├── 01_std_errors │ └── main.go ├── 02_err_is_values │ └── main.go ├── 03_sentinel_errors │ └── main.go ├── 04_err_type │ └── main.go ├── 05_pkg_errors_wrap │ └── main.go ├── 06_pkg_errors_cause │ └── main.go ├── 07_fmt_errorf │ └── main.go ├── 08_errors_unwrap │ └── main.go ├── 09_defer │ └── main.go ├── 10_defer │ └── main.go ├── 11_panic_handle │ └── main.go ├── 13_multierr │ └── main.go ├── 13_multierr_legacy │ └── main.go ├── README.md ├── go.mod └── go.sum ├── 09-interfaces-p1 ├── app.go ├── example │ └── example.go ├── go.mod ├── logger.go └── main.go ├── 09-packages ├── example │ ├── bin │ │ └── mod │ ├── ex │ ├── math2 │ ├── pkg │ │ ├── darwin_amd64 │ │ │ ├── calc.a │ │ │ ├── calc │ │ │ │ └── internal.a │ │ │ └── nousing.a │ │ └── mod │ │ │ ├── cache │ │ │ ├── download │ │ │ │ └── github.com │ │ │ │ │ └── !b!h!y!c!h!i!k │ │ │ │ │ └── testmod │ │ │ │ │ ├── @v │ │ │ │ │ ├── list │ │ │ │ │ ├── list.lock │ │ │ │ │ ├── v1.0.0.info │ │ │ │ │ ├── v1.0.0.lock │ │ │ │ │ ├── v1.0.0.mod │ │ │ │ │ ├── v1.0.0.zip │ │ │ │ │ ├── v1.0.0.ziphash │ │ │ │ │ ├── v1.0.1.info │ │ │ │ │ ├── v1.0.1.lock │ │ │ │ │ ├── v1.0.1.mod │ │ │ │ │ ├── v1.0.1.zip │ │ │ │ │ └── v1.0.1.ziphash │ │ │ │ │ └── v2 │ │ │ │ │ └── @v │ │ │ │ │ ├── list │ │ │ │ │ ├── list.lock │ │ │ │ │ ├── v2.0.2.info │ │ │ │ │ ├── v2.0.2.lock │ │ │ │ │ ├── v2.0.2.mod │ │ │ │ │ ├── v2.0.2.zip │ │ │ │ │ └── v2.0.2.ziphash │ │ │ ├── lock │ │ │ └── vcs │ │ │ │ ├── cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572.info │ │ │ │ ├── cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572.lock │ │ │ │ └── cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572 │ │ │ │ ├── FETCH_HEAD │ │ │ │ ├── HEAD │ │ │ │ ├── config │ │ │ │ ├── description │ │ │ │ ├── hooks │ │ │ │ ├── applypatch-msg.sample │ │ │ │ ├── commit-msg.sample │ │ │ │ ├── post-update.sample │ │ │ │ ├── pre-applypatch.sample │ │ │ │ ├── pre-commit.sample │ │ │ │ ├── pre-push.sample │ │ │ │ ├── pre-rebase.sample │ │ │ │ ├── prepare-commit-msg.sample │ │ │ │ └── update.sample │ │ │ │ ├── info │ │ │ │ ├── attributes │ │ │ │ └── exclude │ │ │ │ ├── objects │ │ │ │ ├── 39 │ │ │ │ │ └── e6bbff8dc4ac0973142faa7cfd39d211539a36 │ │ │ │ ├── 57 │ │ │ │ │ └── f9931e1d91ee5c034bd1d2b51ee73927c9a08f │ │ │ │ ├── 65 │ │ │ │ │ └── 2063eeeb250e50bc7c2ad6c661ab340fcb7d28 │ │ │ │ ├── 85 │ │ │ │ │ └── c155f96fdb72d1a4936d56376edbe38c72f986 │ │ │ │ ├── 02 │ │ │ │ │ └── ea74b485a8afa406a38563367f3d2b539ffec8 │ │ │ │ ├── 07 │ │ │ │ │ ├── 5c39d0531a595a3941f3f7409ce7044cb32ec9 │ │ │ │ │ └── 98c93fd1e96d6b15821aa8753744620636cfd1 │ │ │ │ ├── 2a │ │ │ │ │ └── 65dc2033ef649d8dd7e61a9ebb27a79d1291ac │ │ │ │ ├── 2f │ │ │ │ │ └── 49ad06a932c5b4a4cd646842582ac797ece30d │ │ │ │ ├── 4c │ │ │ │ │ └── e114ad809cacceedde04f6c64b20417e153fd2 │ │ │ │ ├── 7e │ │ │ │ │ └── 4c735d3464013cc11b0099b9320fd849e900df │ │ │ │ ├── ad │ │ │ │ │ └── 79b28f71daa47a2759b47511800457af0f0109 │ │ │ │ ├── b0 │ │ │ │ │ └── 108ce3a7beec624243c91fe1989ed20fcc01b1 │ │ │ │ ├── b9 │ │ │ │ │ └── 7a03123ac2c017ce5918aa80eea113e019b9d3 │ │ │ │ ├── c9 │ │ │ │ │ └── 5cf571c583ff18ec1224ba4b26c2a3eec6881f │ │ │ │ ├── d5 │ │ │ │ │ └── 93a25337a23624a6c68a063ae613f9100e85f2 │ │ │ │ └── ed │ │ │ │ │ └── 56ae4bc0b05310eeeab2d46b04d51c293c6243 │ │ │ │ ├── refs │ │ │ │ └── tags │ │ │ │ │ ├── v1.0.0 │ │ │ │ │ ├── v1.0.1 │ │ │ │ │ ├── v2.0.0 │ │ │ │ │ ├── v2.0.1 │ │ │ │ │ └── v2.0.2 │ │ │ │ └── shallow │ │ │ └── github.com │ │ │ └── !b!h!y!c!h!i!k │ │ │ ├── testmod │ │ │ └── v2@v2.0.2 │ │ │ │ ├── README.md │ │ │ │ ├── go.mod │ │ │ │ └── test.go │ │ │ ├── testmod@v1.0.0 │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ └── test.go │ │ │ └── testmod@v1.0.1 │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ └── test.go │ └── src │ │ ├── calc │ │ ├── antisin.go │ │ ├── internal │ │ │ └── internal.go │ │ ├── mult.go │ │ └── sum.go │ │ ├── ex │ │ └── ex.go │ │ ├── math2 │ │ └── main.go │ │ ├── nousing │ │ └── no.go │ │ └── testsql │ │ ├── Gopkg.lock │ │ ├── Gopkg.toml │ │ ├── main.go │ │ └── vendor │ │ ├── github.com │ │ └── go-sql-driver │ │ │ └── mysql │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── appengine.go │ │ │ ├── auth.go │ │ │ ├── buffer.go │ │ │ ├── collations.go │ │ │ ├── connection.go │ │ │ ├── connection_go18.go │ │ │ ├── const.go │ │ │ ├── driver.go │ │ │ ├── dsn.go │ │ │ ├── errors.go │ │ │ ├── fields.go │ │ │ ├── infile.go │ │ │ ├── packets.go │ │ │ ├── result.go │ │ │ ├── rows.go │ │ │ ├── statement.go │ │ │ ├── transaction.go │ │ │ ├── utils.go │ │ │ ├── utils_go17.go │ │ │ └── utils_go18.go │ │ └── google.golang.org │ │ └── appengine │ │ ├── LICENSE │ │ └── cloudsql │ │ ├── cloudsql.go │ │ ├── cloudsql_classic.go │ │ └── cloudsql_vm.go └── testprog │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── mod │ └── vendor │ ├── github.com │ └── BHYCHIK │ │ └── testmod │ │ └── v2 │ │ ├── README.md │ │ ├── go.mod │ │ └── test.go │ └── modules.txt ├── 10-interfaces-p2 ├── 01-nil │ └── main.go ├── 02-limit-reader │ └── main.go ├── 03-type-assertion │ └── main.go ├── 04-type-switch │ └── main.go ├── 05-privates │ ├── contract │ │ ├── contgract.go │ │ └── int_impl.go │ ├── impl │ │ └── ext_impl.go │ └── main.go ├── 05-sort │ └── main.go ├── 06-refs │ └── main_test.go ├── example │ └── main.go └── go.mod ├── 12-sync-primitives-p1 ├── race │ ├── go.mod │ └── race.go └── race_limit │ ├── go.mod │ └── race_limit.go ├── 13-sync-primitives-p2 └── read_race │ └── main.go ├── 14-concurrency-patterns ├── 1_adhoc │ └── main.go ├── 2_lexical │ └── main.go ├── 3_1_leak │ └── main.go ├── 3_2_done_ch │ └── main.go ├── 3_3_close_data_ch │ └── main.go ├── 4_or_magic │ ├── main.go │ └── or1.go ├── 5_1_handle_err_in_place │ └── main.go ├── 5_2_throw_err_above │ └── main.go ├── 6_1_pipeline │ └── main.go ├── 6_2_stage_constructor │ └── main.go ├── 6_3_stream_pipeline │ └── main.go ├── 6_4_stream_pipeline_with_done │ └── main.go ├── 8_useful_generators │ └── main.go ├── 9_1_prime_finding │ ├── main.go │ ├── prime_finder.go │ ├── repeat_fn.go │ ├── take.go │ └── to_int.go ├── 9_2_fanin_fanout │ ├── fan_in.go │ ├── main.go │ ├── prime_finder.go │ ├── repeat_fn.go │ ├── take.go │ └── to_int.go └── go.mod ├── 16-internals-memory ├── halfsum │ └── main.go ├── heap │ └── main.go ├── stack │ └── main.go └── stack_pointer │ └── main.go ├── 17-input-output ├── exampletest │ ├── example_test.go │ └── testdata │ │ └── example.txt ├── go.mod ├── go.sum ├── readfile │ └── main.go ├── regex │ └── main.go └── writefile │ └── main.go ├── 17-reflection └── main_test.go ├── 18-format ├── base64 │ └── base64.go ├── base64flow │ └── main.go ├── jsonex │ ├── 0_json.go │ ├── 1_json.go │ ├── 2_json.go │ ├── 3_different_rules.go │ ├── 4_recursive_problem.go │ └── 5_raw_message.go ├── msgpackex │ └── ex1.go ├── protobufex │ ├── gen.sh │ ├── main.go │ ├── person.pb.go │ └── person.proto └── xmlex │ ├── sax.go │ ├── xml1.go │ └── xml2.go ├── 19-clean-architecture ├── .gitignore ├── Makefile ├── api │ └── api.proto ├── cmd │ ├── grpc_client.go │ ├── grpc_server.go │ └── root.go ├── go.mod ├── go.sum ├── internal │ ├── adapters │ │ ├── grpc │ │ │ └── api │ │ │ │ ├── api.pb.go │ │ │ │ └── server.go │ │ └── maindb │ │ │ └── maindb.go │ └── domain │ │ ├── entities │ │ └── event.go │ │ ├── errors │ │ └── error.go │ │ ├── interfaces │ │ └── event_storage.go │ │ └── usecases │ │ └── event.go ├── main.go └── sql │ ├── 001.sql │ └── 002.sql ├── 19-os ├── cmd │ └── main.go ├── cmd_pipe │ └── main.go ├── cobra │ └── git2 │ │ ├── LICENSE │ │ ├── cmd │ │ ├── commit.go │ │ └── root.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go ├── env │ └── main.go ├── flag │ └── main.go ├── go.mod ├── go.sum ├── pflag │ └── main.go ├── safefile │ └── main.go ├── signal │ └── main.go └── tmpfiles │ └── main.go ├── 20-reflection ├── 1_value │ └── main.go ├── 2_assert_string │ └── main.go ├── 3_set_value │ └── main.go ├── 4_struct_to_map │ └── main.go ├── 5_map_to_struct │ └── main.go ├── 6_method_list │ └── main.go ├── go.mod └── user │ └── user.go ├── 21-codegen ├── 00-simple │ ├── command.sh │ ├── command.win.bat │ ├── example │ │ └── example.go │ ├── generate.go │ └── main.go ├── 01-bindata │ ├── main.go │ ├── static │ │ └── gopher.png │ └── static_generated.go ├── 02-embed │ ├── main.go │ └── static │ │ └── gopher.png ├── 02a-embed-fs │ ├── main.go │ └── static │ │ ├── gopher.png │ │ └── other.png ├── 03-stringer │ ├── main.go │ └── messagestatus_string.go ├── 04-jsonenums │ ├── main.go │ └── pill_jsonenums.go ├── 05-easyjson │ ├── main.go │ ├── main_test.go │ └── student │ │ ├── student.go │ │ └── student_easyjson.go ├── 06-impl │ └── main.go ├── 07-mockgen │ ├── getter.go │ ├── getter_test.go │ ├── mocks │ │ └── mock_getter.go │ └── option.go ├── 08-genny │ ├── gen-queue_generic.go │ └── queue_generic.go ├── 09-ldflags │ └── main.go ├── 10-protobuf │ ├── Person.pb.go │ ├── Person.proto │ └── main.go ├── 11-ast │ └── main.go ├── go.mod └── go.sum ├── 22-config-n-log ├── config │ ├── config.env │ ├── config.json │ ├── config.toml │ └── config.yml ├── go.mod ├── go.sum ├── jaeger │ └── docker-compose.yml └── src │ ├── 0_base │ └── main.go │ ├── 10_zap_shugar │ └── main.go │ ├── 11_zap_prod │ └── main.go │ ├── 12_zap │ ├── example_test.go │ └── main.go │ ├── 13_slog │ ├── main.go │ └── slog_test.go │ ├── 1_env │ └── main.go │ ├── 2_caarlos-env │ └── main.go │ ├── 3_confita │ └── main.go │ ├── 4_viper │ └── main.go │ ├── 4a_viper │ ├── config.yaml │ └── main.go │ ├── 5_log1 │ └── main.go │ ├── 6_log2 │ └── main.go │ ├── 7_logrus │ └── main.go │ ├── 8_zap │ └── main.go │ └── 9_zap │ └── main.go ├── 23-no-sql ├── Dockerfile ├── aerospike │ └── main.go ├── clickhouse │ └── main.go ├── docker-compose.yaml ├── go.mod ├── go.sum ├── mongo │ ├── main.go │ └── social-media │ │ └── main.go └── redis │ ├── broker │ └── main.go │ └── main.go ├── 23-profiling ├── 00_lesson │ ├── ex1_slice_test.go │ ├── ex2_to_str_test.go │ ├── ex3_conc_test.go │ ├── ex4_concat_string_test.go │ ├── ex5_match_test.go │ ├── ex6_obj_reuse_test.go │ ├── go.mod │ ├── optimization │ │ ├── go.mod │ │ ├── go.sum │ │ ├── top10.go │ │ └── top10_test.go │ └── pprofsrv │ │ └── main.go ├── 01_bench │ ├── ex.txt │ ├── exbench.go │ └── exbench_test.go ├── 02_benchpar │ ├── benchpar.go │ ├── ex.txt │ └── exbenchpar_test.go ├── 03_prealloc │ ├── prealloc.go │ └── prealloc_test.go ├── 04_reuse │ ├── reuse.go │ └── reuse_test.go ├── 05_fmtvsstrconv │ ├── fmtvsstrconv.go │ └── fmtvsstrconv_test.go ├── 06_stringsvsre │ ├── stringsvsre.go │ └── stringsvsre_test.go ├── 07_stringbuilder │ ├── stringbuilder.go │ └── stringbuilder_test.go ├── 08_syncpool │ ├── syncpool.go │ └── syncpool_test.go ├── 09_pointerkeys │ └── pointerkeys.go ├── 10_exjs │ ├── exjs.go │ ├── exjs_easyjson.go │ └── exjs_test.go ├── 11_generics │ ├── generics.go │ └── generics_test.go ├── 12_httpserver │ ├── fast.go │ ├── standard.go │ └── test.txt ├── 13_pprof_console │ ├── 13_pprof_console.test │ ├── cpu.out │ ├── help.txt │ ├── mem.out │ ├── prealloc.go │ └── prealloc_test.go ├── 14_pprof_svg_and_web │ ├── help.txt │ └── standard.go ├── 15_flamegraph │ ├── help.txt │ └── standard.go └── 16_trace │ ├── help.txt │ ├── standard.go │ └── trace.out ├── 24-context-n-net ├── 01-tcp-chat │ └── chat.go ├── 02-chat-client │ └── client.go ├── 03-udp-server │ └── udpserver.go ├── 04-udp-client │ └── client.go ├── 05-dns-resolver │ └── resolve.go ├── 06-context │ └── context.go ├── 06b-context │ └── context.go ├── 07-signal-notyfy-context │ └── signal.go ├── 08-gracefull-stop │ └── gracefullstop.go ├── 09-context-with-value │ └── context_with_value.go ├── 10-context-with-cancel │ └── context_with_cancel.go ├── 11-context-with-timeout │ └── context_with_timeout.go └── 12-context-with-deadline │ └── context-with-deadline.go ├── 25-sql ├── cmd │ └── app │ │ └── main.go ├── commands.txt ├── configs │ └── local.toml ├── go.mod ├── go.sum ├── internal │ ├── app │ │ └── app.go │ ├── config │ │ └── config.go │ └── repository │ │ ├── psql │ │ └── repository.go │ │ └── repository.go └── migrations │ └── 20200528084542_init.sql ├── 26-grpc-2 ├── chat │ ├── api │ │ ├── chat.go │ │ └── proto │ │ │ ├── chat.pb.go │ │ │ ├── chat.proto │ │ │ └── chat_grpc.pb.go │ ├── client │ │ └── main.go │ ├── go.mod │ ├── go.sum │ └── server │ │ └── main.go ├── int-sint │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── main_test.go │ └── proto │ │ ├── benchmark.pb.go │ │ └── benchmark.proto └── taskmanager │ ├── api │ ├── proto │ │ ├── taskmanager.pb.go │ │ ├── taskmanager.proto │ │ └── taskmanager_grpc.pb.go │ └── taskmanager.go │ ├── client │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── internal │ └── task │ │ ├── handler.go │ │ └── service.go │ └── server │ └── main.go ├── 26-http ├── client-func-method │ └── main.go ├── client-ws │ └── main.go ├── client │ ├── main.go │ └── main_test.go ├── go.mod ├── go.sum ├── handler │ ├── handler.go │ └── handler_test.go ├── middleware-abstract │ ├── abstract_middleware.go │ ├── abstract_middleware_test.go │ └── middleware_lib.go ├── middleware │ ├── client.go │ └── server.go ├── server-mux │ └── main.go └── server │ ├── main.go │ └── server_test.go ├── 27-grpc ├── Makefile ├── api │ ├── elections-with-admin │ │ └── elections.proto │ ├── elections-with-stats │ │ └── elections.proto │ └── elections │ │ └── elections.proto ├── elections-with-admin │ ├── elections.pb.go │ ├── elections_grpc.pb.go │ ├── main.go │ ├── service.go │ └── validate.go ├── elections-with-stats │ ├── elections.pb.go │ ├── elections_grpc.pb.go │ ├── main.go │ └── service.go ├── elections │ ├── client │ │ └── main.go │ ├── pb │ │ ├── elections.pb.go │ │ └── elections_grpc.pb.go │ ├── server │ │ └── main.go │ └── validate │ │ └── validate.go ├── go.mod ├── go.sum └── tools.go ├── 27-websockets ├── README.md └── src │ ├── 1 │ ├── go.mod │ ├── go.sum │ └── main.go │ └── 2 │ ├── client │ ├── go.mod │ ├── go.sum │ └── main.go │ └── server │ ├── go.mod │ ├── go.sum │ └── main.go ├── 29-queues ├── Makefile ├── consumer │ └── consumer.go ├── consumer_reconnect │ └── consumer.go ├── consumer_short │ ├── consumer │ │ └── consumer.go │ └── main.go ├── go.mod ├── go.sum └── producer │ ├── main.go │ ├── producer.go │ └── producer_sync_confirm.go ├── 31-integration-testing ├── Makefile ├── README.md ├── assets │ └── user_reg_event.png ├── cmd │ ├── notification-service │ │ ├── Dockerfile │ │ ├── config.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── sender.go │ └── registration-service │ │ ├── Dockerfile │ │ ├── config.go │ │ ├── db.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ ├── rmq.go │ │ └── server.go ├── config.toml ├── configs │ ├── rabbit.config │ └── rabbit.def.json ├── docker-compose.test.yml ├── docker-compose.yml ├── scripts │ └── setup.sql └── tests │ ├── Dockerfile │ ├── features │ └── notification.feature │ ├── go.mod │ ├── go.sum │ ├── main_test.go │ └── notification_test.go ├── 32-monitoring ├── Dockerfile ├── Makefile ├── docker-compose.yml ├── go.mod ├── go.sum ├── main.go ├── metrics.go └── prometheus.yaml ├── LITERATURE.md └── open-lesson └── interfaces ├── 02_refs └── refs_test.go ├── 03_receivers ├── dark_test.go └── receivers_test.go ├── 04_type_assertion └── type_assertion_test.go ├── 05_type_switch └── type_switch_test.go └── go.mod /.gitignore: -------------------------------------------------------------------------------- 1 | # Test binary, build with `go test -c` 2 | *.test 3 | 4 | # Output of the go coverage tool, specifically when used with LiteIDE 5 | *.out 6 | 7 | ### User defined 8 | .idea/ 9 | .DS_Store 10 | .DS_Store? 11 | ._* 12 | .Spotlight-V100 13 | .Trashes 14 | ehthumbs.db 15 | Thumbs.db 16 | .vscode/ 17 | -------------------------------------------------------------------------------- /01-first-go-program/README.md: -------------------------------------------------------------------------------- 1 | Простая программа на языке Golang, осуществляющая конкурентный 2 | поиск новостей в RSS-лентах по ключевому слову. 3 | 4 | Пример работы: 5 | ```bash 6 | $ go run . 7 | Process https://news.yandex.ru/army.rss... 8 | Process https://news.yandex.ru/business.rss... 9 | Process https://news.yandex.ru/basketball.rss... 10 | Process https://news.yandex.ru/biathlon.rss... 11 | Process https://news.yandex.ru/world.rss... 12 | Process https://news.yandex.ru/auto.rss... 13 | 14 | Госстрой Башкирии представил первый опыт использования банка земли (https://yandex.ru/news/story/Gosstroj_Bashkirii_) 15 | 16 | Сбербанк выдает крымчанам ипотеку, но не признается (https://yandex.ru/news/story/Sberbank_vydaet_krymch) 17 | 18 | В Белгороде улучшат обстановку на дорогах на «Богданке» (https://yandex.ru/news/story/V_Belgorode_uluchshat_obstan) 19 | ``` 20 | -------------------------------------------------------------------------------- /01-first-go-program/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/01-first-go-program 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /01-first-go-program/main.go: -------------------------------------------------------------------------------- 1 | package main // Текущий пакет 2 | 3 | // Импортируем пакеты 4 | import ( 5 | "os" // Пакет для работы с ОС из стандартной библиотеки Go 6 | // Пакет "searcher" нашего модуля "github.com/OtusGolang/webinars_practical_part/01-first-go-program" 7 | "github.com/OtusGolang/webinars_practical_part/01-first-go-program/searcher" 8 | ) 9 | 10 | // Константа уровня пакета 11 | const keyword = "чиновник" 12 | 13 | // «Точка входа» в программу 14 | func main() { 15 | // Вызываем функцию "Search" из пакета "searcher" 16 | searcher.Search(feeds, keyword, os.Stdout) 17 | } 18 | -------------------------------------------------------------------------------- /03-unit-testing/mock/db.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | //go:generate mockgen -destination=mock_db_test.go -package=mock_test . UsersDB 4 | 5 | type UsersDB interface { 6 | AddUser(user User) error 7 | FindUser(id string) (User, error) 8 | } 9 | -------------------------------------------------------------------------------- /03-unit-testing/mock/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/otus/mock 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/golang/mock v1.6.0 7 | github.com/stretchr/testify v1.7.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.0 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /03-unit-testing/mock/models.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | type User struct { 4 | ID string 5 | Name string 6 | Phone string 7 | } 8 | -------------------------------------------------------------------------------- /03-unit-testing/mock/store.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import "fmt" 4 | 5 | type UserStore struct { 6 | db UsersDB 7 | } 8 | 9 | func NewUserStore(db UsersDB) *UserStore { 10 | return &UserStore{ 11 | db: db, 12 | } 13 | } 14 | 15 | func (s *UserStore) Duplicate(userID string) (string, error) { 16 | user, err := s.db.FindUser(userID) 17 | if err != nil { 18 | return "", fmt.Errorf("failed to find user: %w", err) 19 | } 20 | 21 | user.ID = user.ID + "_" 22 | err = s.db.AddUser(user) 23 | return user.ID, err 24 | } 25 | -------------------------------------------------------------------------------- /03-unit-testing/mock_faker/db.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | //go:generate mockgen -destination=mock_db_test.go -package=mock_test . UsersDB 4 | 5 | type UsersDB interface { 6 | AddUser(user User) error 7 | FindUser(id string) (User, error) 8 | } 9 | -------------------------------------------------------------------------------- /03-unit-testing/mock_faker/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/otus/mock 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/bxcodec/faker/v3 v3.3.1 7 | github.com/golang/mock v1.6.0 8 | github.com/stretchr/testify v1.7.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /03-unit-testing/mock_faker/models.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | type User struct { 4 | ID string 5 | Name string 6 | Phone string 7 | } 8 | -------------------------------------------------------------------------------- /03-unit-testing/mock_faker/store.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import "fmt" 4 | 5 | type UserStore struct { 6 | db UsersDB 7 | } 8 | 9 | func NewUserStore(db UsersDB) *UserStore { 10 | return &UserStore{ 11 | db: db, 12 | } 13 | } 14 | 15 | func (s *UserStore) Duplicate(userID string) (string, error) { 16 | user, err := s.db.FindUser(userID) 17 | if err != nil { 18 | return "", fmt.Errorf("failed to find user: %w", err) 19 | } 20 | 21 | user.ID = user.ID + "_" 22 | err = s.db.AddUser(user) 23 | return user.ID, err 24 | } 25 | -------------------------------------------------------------------------------- /03-unit-testing/mock_suite/db.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | //go:generate mockgen -destination=mock_db_test.go -package=mock_test . UsersDB 4 | 5 | type UsersDB interface { 6 | AddUser(user User) error 7 | FindUser(id string) (User, error) 8 | } 9 | -------------------------------------------------------------------------------- /03-unit-testing/mock_suite/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/otus/mock 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/golang/mock v1.6.0 7 | github.com/stretchr/testify v1.7.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.0 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /03-unit-testing/mock_suite/models.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | type User struct { 4 | ID string 5 | Name string 6 | Phone string 7 | } 8 | -------------------------------------------------------------------------------- /03-unit-testing/mock_suite/store.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import "fmt" 4 | 5 | type UserStore struct { 6 | db UsersDB 7 | } 8 | 9 | func NewUserStore(db UsersDB) *UserStore { 10 | return &UserStore{ 11 | db: db, 12 | } 13 | } 14 | 15 | func (s *UserStore) Duplicate(userID string) (string, error) { 16 | user, err := s.db.FindUser(userID) 17 | if err != nil { 18 | return "", fmt.Errorf("failed to find user: %w", err) 19 | } 20 | 21 | user.ID = user.ID + "_" 22 | err = s.db.AddUser(user) 23 | return user.ID, err 24 | } 25 | -------------------------------------------------------------------------------- /03-unit-testing/time/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/otus/otime 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/benbjohnson/clock v1.0.3 7 | github.com/cabify/timex v1.0.0 8 | github.com/stretchr/testify v1.7.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /04-simple-data-types/example/example.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | func Answer() int { 4 | return 42 5 | } 6 | 7 | func unexported() (int, int) { 8 | return 10, 11 9 | } 10 | -------------------------------------------------------------------------------- /04-simple-data-types/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/04-simple-data-types 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /04-simple-data-types/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/04-simple-data-types/go.sum -------------------------------------------------------------------------------- /04-simple-data-types/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/OtusGolang/webinars_practical_part/04-simple-data-types/example" 6 | "github.com/OtusGolang/webinars_practical_part/04-simple-data-types/runes" 7 | ) 8 | 9 | var i float32 = 42 10 | 11 | func notNakedReturn() (a int, b bool) { 12 | return 13 | } 14 | 15 | func main() { 16 | j := example.Answer() 17 | fmt.Println(j) 18 | fmt.Println(1 - 0.8 - 0.2) 19 | 20 | fmt.Println() 21 | runes.Example() 22 | } 23 | -------------------------------------------------------------------------------- /04-simple-data-types/runes/runes.go: -------------------------------------------------------------------------------- 1 | package runes 2 | 3 | import "fmt" 4 | 5 | func Example() { 6 | //s := "Jack" 7 | //s := "Джек" 8 | s := "Дже♫к" 9 | for i, val := range s { 10 | fmt.Printf("%d %s %d\n", i, string(val), val) 11 | } 12 | fmt.Println("LEN: ", len(s)) 13 | } 14 | -------------------------------------------------------------------------------- /05-structures/child/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Base struct{} 8 | 9 | func (b Base) Name() string { 10 | return "Base" 11 | } 12 | 13 | func (b Base) Say() { 14 | fmt.Println(b.Name()) 15 | } 16 | 17 | type Child struct { 18 | Base 19 | } 20 | 21 | func (c Child) Name() string { 22 | return "Child" 23 | } 24 | 25 | func main() { 26 | var c Child 27 | c.Say() // ? 28 | } 29 | -------------------------------------------------------------------------------- /05-structures/country/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type countriesCodes map[string]int 8 | 9 | type world struct { 10 | Name string 11 | countries countriesCodes 12 | } 13 | 14 | func NewWorld(name string) *world { 15 | w := world{ 16 | Name: name, 17 | countries: make(countriesCodes), 18 | } 19 | return &w 20 | } 21 | 22 | func (w *world) AddCountry(name string, code int) { 23 | w.countries[name] = code 24 | } 25 | 26 | func (w world) GetCountryCode(name string) (code int, ok bool) { 27 | code, ok = w.countries[name] 28 | return 29 | } 30 | 31 | func main() { 32 | w := NewWorld("Earth") 33 | w.AddCountry("Russia", 666) 34 | c, _ := w.GetCountryCode("Russia") 35 | fmt.Println(c) // 666 36 | } 37 | -------------------------------------------------------------------------------- /05-structures/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/05-structures 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /05-structures/market/market.go: -------------------------------------------------------------------------------- 1 | package market 2 | 3 | type Bucket struct { 4 | Width, Height int 5 | Wheels []wheel 6 | number int 7 | } 8 | 9 | func NewWheel() wheel { 10 | return wheel{} 11 | } 12 | 13 | type wheel struct { 14 | R float64 15 | s float64 16 | } 17 | -------------------------------------------------------------------------------- /05-structures/pets/pets.go: -------------------------------------------------------------------------------- 1 | package pets 2 | 3 | type Cat struct { 4 | Name string 5 | weight float64 6 | } 7 | 8 | type Tiger struct { 9 | Cat 10 | } 11 | -------------------------------------------------------------------------------- /05-structures/stack/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type IntStack struct { 8 | stack []int 9 | } 10 | 11 | func (s *IntStack) Push(v int) { 12 | s.stack = append(s.stack, v) 13 | } 14 | 15 | func (s *IntStack) Pop() int { 16 | if len(s.stack) == 0 { 17 | return 0 18 | } 19 | v := s.stack[len(s.stack)-1] 20 | s.stack = s.stack[:len(s.stack)-1] 21 | return v 22 | } 23 | 24 | func main() { 25 | var s IntStack 26 | s.Push(10) 27 | s.Push(20) 28 | s.Push(30) 29 | fmt.Printf("expected 30, got %d\n", s.Pop()) 30 | fmt.Printf("expected 20, got %d\n", s.Pop()) 31 | fmt.Printf("expected 10, got %d\n", s.Pop()) 32 | fmt.Printf("expected 0, got %d\n", s.Pop()) 33 | } 34 | -------------------------------------------------------------------------------- /05-structures/user.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type User struct { // Структура с именованными полями 4 | Id int64 5 | Name string 6 | Age int 7 | friends []int64 // Приватный элемент 8 | } 9 | 10 | func (u *User) HappyBirthday() { 11 | u.Age++ 12 | } 13 | -------------------------------------------------------------------------------- /05-testing/asserts_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestAssertReporting(t *testing.T) { 11 | 12 | var err error = io.EOF 13 | // ... 14 | 15 | assert.NoError(t, err) 16 | assert.Nil(t, err) 17 | assert.True(t, err == nil) 18 | } 19 | -------------------------------------------------------------------------------- /05-testing/err_and_fatal_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "testing" 8 | ) 9 | 10 | func TestAtoi(t *testing.T) { 11 | os.Getwd() 12 | const str, want = "43a", 42 13 | got, err := strconv.Atoi(str) 14 | if err != nil { 15 | t.Fatalf("strconv.Atoi(%q) returns unexpeted error: %v", str, err) 16 | } 17 | if got != want { 18 | t.Errorf("strconv.Atoi(%q) = %v; want %v", str, got, want) 19 | } 20 | 21 | fmt.Printf("The end of the test") 22 | } 23 | -------------------------------------------------------------------------------- /05-testing/golden_files/testdata/Aunt Mildred.golden: -------------------------------------------------------------------------------- 1 | 2 | Dear Aunt Mildred, 3 | 4 | It was a pleasure to see you at the wedding. 5 | Thank you for the lovely bone china tea set. 6 | 7 | Best wishes, 8 | Josie 9 | -------------------------------------------------------------------------------- /05-testing/golden_files/testdata/Cousin Rodney.golden: -------------------------------------------------------------------------------- 1 | 2 | Dear Cousin Rodney, 3 | 4 | It is a shame you couldn't make it to the wedding. 5 | 6 | Best wishes, 7 | Josie 8 | -------------------------------------------------------------------------------- /05-testing/golden_files/testdata/Uncle John.golden: -------------------------------------------------------------------------------- 1 | 2 | Dear Uncle John, 3 | 4 | It is a shame you couldn't make it to the wedding. 5 | Thank you for the lovely moleskin pants. 6 | 7 | Best wishes, 8 | Josie 9 | -------------------------------------------------------------------------------- /05-testing/titlecase_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/kulti/titlecase" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | // TitleCase(str, minor) returns a str string with all words capitalized except minor words. 11 | // The first word is always capitalized. 12 | // 13 | // E.g. 14 | // TitleCase("the quick fox in the bag", "") = "The Quick Fox In The Bag" 15 | // TitleCase("the quick fox in the bag", "in the") = "The Quick Fox in the Bag" 16 | 17 | // Задание 18 | // 1. Дописать существующие тесты. 19 | // 2. Придумать один новый тест. 20 | 21 | func TestEmpty(t *testing.T) { 22 | const str, minor, want = "", "", "" 23 | got := titlecase.TitleCase(str, minor) 24 | assert.Equal(t, want, got) 25 | } 26 | 27 | func TestWithoutMinor(t *testing.T) { 28 | panic("implement me") 29 | } 30 | 31 | func TestWithMinorInFirst(t *testing.T) { 32 | panic("implement me") 33 | } 34 | -------------------------------------------------------------------------------- /05-testing/utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func CommonUtil() { 6 | 7 | fmt.Printf("Common Util\n") 8 | 9 | if false { 10 | fmt.Printf("This will never print\n") 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /08-errors-handling/01_std_errors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func foo() (bool, error) { 9 | return false, errors.New("foo failed") 10 | } 11 | 12 | func bar() (bool, error) { 13 | return false, fmt.Errorf("user %q not found", "test") 14 | } 15 | 16 | func main() { 17 | _, err := foo() 18 | if err != nil { 19 | fmt.Println(err) 20 | } 21 | 22 | if _, err := bar(); err != nil { 23 | fmt.Println(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /08-errors-handling/02_err_is_values/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type Checker struct { 9 | err error 10 | matched int 11 | } 12 | 13 | func (c *Checker) Step(s string) { 14 | if c.err != nil { 15 | return 16 | } 17 | 18 | if len(s) == 0 { 19 | c.err = errors.New("empty string") 20 | return 21 | } 22 | 23 | c.matched++ 24 | } 25 | 26 | func (c *Checker) Error() error { 27 | return c.err 28 | } 29 | 30 | func main() { 31 | c := &Checker{} 32 | records := []string{"foo", "bar", "", "test"} 33 | 34 | for _, r := range records { 35 | c.Step(r) 36 | } 37 | 38 | if err := c.Error(); err != nil { 39 | fmt.Println(err) 40 | return 41 | } 42 | 43 | fmt.Printf("OK: %d", c.matched) 44 | } 45 | -------------------------------------------------------------------------------- /08-errors-handling/03_sentinel_errors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | r := strings.NewReader("hello world!") 11 | 12 | buf := make([]byte, 5) 13 | if _, err := io.ReadFull(r, buf); err != nil { 14 | fmt.Println(err) 15 | } else { 16 | fmt.Println(string(buf)) 17 | } 18 | 19 | longBuf := make([]byte, 64) 20 | if _, err := io.ReadFull(r, longBuf); err != nil { 21 | fmt.Println("error:", err) 22 | } else { 23 | fmt.Println("ok") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /08-errors-handling/04_err_type/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | type PathError struct { 9 | Op string // "open", "unlink", etc. 10 | Path string // The associated file. 11 | Err error 12 | } 13 | 14 | func (e *PathError) Error() string { 15 | return e.Op + " " + e.Path + " " + e.Err.Error() 16 | } 17 | 18 | func checkConfig(path string) error { 19 | _, err := os.ReadFile(path) 20 | if err != nil { 21 | return &PathError{"open", path, err} 22 | } 23 | 24 | return nil 25 | } 26 | 27 | func main() { 28 | err := checkConfig("/etc/apt/sources.list") 29 | 30 | switch err := err.(type) { // prefer errors.As 31 | case *PathError: 32 | fmt.Println("path error: ", err) 33 | case nil: 34 | fmt.Println("success") 35 | default: 36 | fmt.Println("unknown error") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /08-errors-handling/05_pkg_errors_wrap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | const testEmail = "test@mail.ru" 10 | 11 | func getUserEmail(id int) (string, error) { 12 | if id == 1 { 13 | return testEmail, nil 14 | } 15 | 16 | return "", errors.New("email not found") 17 | } 18 | 19 | func loginUserById(id int) (bool, error) { 20 | email, err := getUserEmail(id) 21 | if err != nil { 22 | return false, errors.Wrap(err, "unable to get email") 23 | } 24 | 25 | if email != testEmail { 26 | return false, errors.New("unable to login user") 27 | } 28 | 29 | return true, nil 30 | } 31 | 32 | func main() { 33 | if _, err := loginUserById(0); err != nil { 34 | fmt.Printf("%+v\n", err) 35 | } else { 36 | fmt.Println("success") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /08-errors-handling/06_pkg_errors_cause/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | const testEmail = "test@mail.ru" 10 | 11 | type UserNotFound struct{} 12 | 13 | func (e UserNotFound) Error() string { 14 | return "user not found" 15 | } 16 | 17 | func getUserEmail(id int) (string, error) { 18 | if id == 1 { 19 | return testEmail, nil 20 | } 21 | 22 | return "", UserNotFound{} 23 | } 24 | 25 | func loginUserById(id int) (bool, error) { 26 | email, err := getUserEmail(id) 27 | if err != nil { 28 | return false, errors.Wrap(err, "unable to get email") 29 | } 30 | 31 | if email != testEmail { 32 | return false, errors.New("unable to login user") 33 | } 34 | 35 | return true, nil 36 | } 37 | 38 | func main() { 39 | _, err := loginUserById(0) 40 | 41 | switch err := errors.Cause(err).(type) { 42 | case UserNotFound: 43 | fmt.Println("unable to find user: ", err) 44 | case nil: 45 | fmt.Println("success") 46 | default: 47 | fmt.Println("unkown error") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /08-errors-handling/07_fmt_errorf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const testEmail = "test@mail.ru" 8 | 9 | func getUserEmail(id int) (string, error) { 10 | if id == 1 { 11 | return testEmail, nil 12 | } 13 | 14 | return "", fmt.Errorf("email not found") 15 | } 16 | 17 | func loginUserById(id int) (bool, error) { 18 | email, err := getUserEmail(id) 19 | if err != nil { 20 | return false, fmt.Errorf("unable to get email: %w", err) 21 | } 22 | 23 | if email != testEmail { 24 | return false, fmt.Errorf("unable to login user") 25 | } 26 | 27 | return true, nil 28 | } 29 | 30 | func main() { 31 | if _, err := loginUserById(123); err != nil { 32 | fmt.Printf("%+v\n", err) 33 | } else { 34 | fmt.Println("success") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /08-errors-handling/08_errors_unwrap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | const testEmail = "test@mail.ru" 9 | 10 | type UserNotFound struct{} 11 | 12 | func (e *UserNotFound) Error() string { 13 | return "user not found" 14 | } 15 | 16 | func getUserEmail(id int) (string, error) { 17 | if id == 1 { 18 | return testEmail, nil 19 | } 20 | 21 | return "", &UserNotFound{} 22 | } 23 | 24 | func loginUserById(id int) (bool, error) { 25 | email, err := getUserEmail(id) 26 | if err != nil { 27 | return false, fmt.Errorf("unable to get email: %w", err) 28 | } 29 | 30 | if email != testEmail { 31 | return false, fmt.Errorf("unable to login user") 32 | } 33 | 34 | return true, nil 35 | } 36 | 37 | func main() { 38 | _, err := loginUserById(0) 39 | 40 | switch err := errors.Unwrap(err).(type) { 41 | case *UserNotFound: 42 | fmt.Println("unable to find user: ", err) 43 | case nil: 44 | fmt.Println("success") 45 | default: 46 | fmt.Println("unknown error") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /08-errors-handling/09_defer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func calcSum(r []int) int { 8 | count := 0 9 | defer func() { 10 | fmt.Printf("elements count: %d\n", count) 11 | }() 12 | 13 | sum := 0 14 | for _, rr := range r { 15 | sum += rr 16 | count++ 17 | } 18 | 19 | return sum 20 | } 21 | 22 | func main() { 23 | r := []int{1, 2, 3, 4, 5} 24 | sum := calcSum(r) 25 | fmt.Println(sum) 26 | } 27 | -------------------------------------------------------------------------------- /08-errors-handling/10_defer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func process(r []int) { 6 | for _, rr := range r { 7 | defer fmt.Printf("finish processing for %d\n", rr) 8 | fmt.Printf("processing %d\n", rr) 9 | } 10 | } 11 | 12 | func main() { 13 | r := []int{1, 2} 14 | process(r) 15 | } 16 | -------------------------------------------------------------------------------- /08-errors-handling/11_panic_handle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log/slog" 5 | ) 6 | 7 | func server(workChan <-chan int) { 8 | for work := range workChan { 9 | go safelyDo(work) 10 | } 11 | } 12 | 13 | func safelyDo(work int) { 14 | defer func() { 15 | slog.Info("work is done", "work", work) 16 | 17 | // if err := recover(); err != nil { 18 | // slog.Info("work failed: ", "error", err) 19 | // } 20 | }() 21 | 22 | do(work) 23 | } 24 | 25 | func do(work int) { 26 | slog.Info("success", "work", work) 27 | // panic("failed") 28 | } 29 | 30 | func main() { 31 | workChan := make(chan int) 32 | defer close(workChan) 33 | 34 | go server(workChan) 35 | 36 | for i := 0; i < 10; i++ { 37 | workChan <- i 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /08-errors-handling/13_multierr/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var Err42 = errors.New("oh no, it is the 42 error") 9 | 10 | func main() { 11 | err := doManyRollbacks() 12 | if err != nil { 13 | fmt.Println("Error: ", err) 14 | } 15 | if errors.Is(err, Err42) { 16 | fmt.Println("42 is in there! 'Is' works for multierrors!") 17 | } 18 | 19 | } 20 | 21 | func doManyRollbacks() error { 22 | var mErr []error 23 | for _, rollbackReq := range prepareRollbackRequests() { 24 | mErr = append(mErr, rollback(rollbackReq)) 25 | } 26 | return fmt.Errorf("mass rollback: %w", errors.Join(mErr...)) 27 | } 28 | 29 | func prepareRollbackRequests() []interface{} { 30 | return []interface{}{42, 43, 44} 31 | } 32 | 33 | func rollback(v interface{}) error { 34 | // do something... 35 | 36 | if v == 42 { 37 | return Err42 38 | } 39 | 40 | return fmt.Errorf("uh oh %v", v) // try this 41 | } 42 | -------------------------------------------------------------------------------- /08-errors-handling/13_multierr_legacy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/go-multierror" 6 | ) 7 | 8 | func main() { 9 | var mErr error 10 | for _, rollbackReq := range prepareRollbackRequests() { 11 | mErr = multierror.Append(mErr, rollback(rollbackReq)) 12 | } 13 | fmt.Println(mErr == nil) 14 | } 15 | 16 | func prepareRollbackRequests() []interface{} { 17 | return []interface{}{42} 18 | } 19 | 20 | func rollback(interface{}) error { 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /08-errors-handling/README.md: -------------------------------------------------------------------------------- 1 | Набор простых примеров, демонстрирующих работу с ошибками в языке Golang. 2 | Сюда же входит несколько примеров с defer, panic, recover. 3 | -------------------------------------------------------------------------------- /08-errors-handling/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/08-errors-handling 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/hashicorp/go-multierror v1.1.1 7 | github.com/pkg/errors v0.9.1 8 | ) 9 | 10 | require github.com/hashicorp/errwrap v1.0.0 // indirect 11 | -------------------------------------------------------------------------------- /08-errors-handling/go.sum: -------------------------------------------------------------------------------- 1 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 2 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 3 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 4 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 5 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 6 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 7 | -------------------------------------------------------------------------------- /09-interfaces-p1/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type App struct { 4 | Log Logger 5 | } 6 | 7 | func (a *App) Run() error { 8 | return a.Log.LogToFile("Hello") 9 | } 10 | -------------------------------------------------------------------------------- /09-interfaces-p1/example/example.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import "fmt" 4 | 5 | type Greeter interface { 6 | hello() int 7 | } 8 | 9 | type Stranger interface { 10 | Bye() string 11 | Greeter 12 | fmt.Stringer 13 | } 14 | -------------------------------------------------------------------------------- /09-interfaces-p1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/09-interfaces 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /09-interfaces-p1/logger.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | ) 7 | 8 | type Logger struct { 9 | Level int 10 | File *os.File 11 | Buf *bytes.Buffer 12 | } 13 | 14 | func (l Logger) LogToFile(msg string) error { 15 | _, err := l.File.Write([]byte(msg)) 16 | return err 17 | } 18 | 19 | func (l Logger) LogToBuffer(msg string) error { 20 | l.Buf.Write([]byte(msg)) 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /09-interfaces-p1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | a := &App{ 11 | Log: Logger{ 12 | File: os.Stdout, 13 | Buf: new(bytes.Buffer), 14 | }, 15 | } 16 | if err := a.Run(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /09-packages/example/bin/mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/bin/mod -------------------------------------------------------------------------------- /09-packages/example/ex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/ex -------------------------------------------------------------------------------- /09-packages/example/math2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/math2 -------------------------------------------------------------------------------- /09-packages/example/pkg/darwin_amd64/calc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/darwin_amd64/calc.a -------------------------------------------------------------------------------- /09-packages/example/pkg/darwin_amd64/calc/internal.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/darwin_amd64/calc/internal.a -------------------------------------------------------------------------------- /09-packages/example/pkg/darwin_amd64/nousing.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/darwin_amd64/nousing.a -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/list: -------------------------------------------------------------------------------- 1 | v1.0.0 2 | v1.0.1 3 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/list.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/list.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.info: -------------------------------------------------------------------------------- 1 | {"Version":"v1.0.0","Time":"2019-06-27T18:08:38Z"} -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.zip -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.0.ziphash: -------------------------------------------------------------------------------- 1 | h1:ZD/UgYAf6bqlduk7l05KdZ3ByGNmRG/VT4GFa6NY9pU= -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.info: -------------------------------------------------------------------------------- 1 | {"Version":"v1.0.1","Time":"2019-06-27T18:15:36Z"} -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.zip -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/@v/v1.0.1.ziphash: -------------------------------------------------------------------------------- 1 | h1:hiufhPz6B+H7oCfas4W7tkFDkKKnx1J1ch2nHBWeNOs= -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/list: -------------------------------------------------------------------------------- 1 | v2.0.2 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/list.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/list.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.info: -------------------------------------------------------------------------------- 1 | {"Version":"v2.0.2","Time":"2019-06-27T18:26:36Z"} -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod/v2 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.zip -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/download/github.com/!b!h!y!c!h!i!k/testmod/v2/@v/v2.0.2.ziphash: -------------------------------------------------------------------------------- 1 | h1:wzOgDwFT+LRyEveQAAdesosIfXzCSNcOKgzoDZC8E6M= -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572.info: -------------------------------------------------------------------------------- 1 | git2:https://github.com/BHYCHIK/testmod -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572.lock -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/FETCH_HEAD: -------------------------------------------------------------------------------- 1 | b0108ce3a7beec624243c91fe1989ed20fcc01b1 tag 'v2.0.2' of https://github.com/BHYCHIK/testmod 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = true 5 | ignorecase = true 6 | precomposeunicode = true 7 | [remote "origin"] 8 | url = https://github.com/BHYCHIK/testmod 9 | fetch = +refs/heads/*:refs/remotes/origin/* 10 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/hooks/applypatch-msg.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to check the commit log message taken by 4 | # applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. The hook is 8 | # allowed to edit the commit message file. 9 | # 10 | # To enable this hook, rename this file to "applypatch-msg". 11 | 12 | . git-sh-setup 13 | test -x "$GIT_DIR/hooks/commit-msg" && 14 | exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} 15 | : 16 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/hooks/post-update.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to prepare a packed repository for use over 4 | # dumb transports. 5 | # 6 | # To enable this hook, rename this file to "post-update". 7 | 8 | exec git update-server-info 9 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/hooks/pre-applypatch.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An example hook script to verify what is about to be committed 4 | # by applypatch from an e-mail message. 5 | # 6 | # The hook should exit with non-zero status after issuing an 7 | # appropriate message if it wants to stop the commit. 8 | # 9 | # To enable this hook, rename this file to "pre-applypatch". 10 | 11 | . git-sh-setup 12 | test -x "$GIT_DIR/hooks/pre-commit" && 13 | exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} 14 | : 15 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/info/attributes: -------------------------------------------------------------------------------- 1 | 2 | * -export-subst -export-ignore 3 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/info/exclude: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/02/ea74b485a8afa406a38563367f3d2b539ffec8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/02/ea74b485a8afa406a38563367f3d2b539ffec8 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/07/5c39d0531a595a3941f3f7409ce7044cb32ec9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/07/5c39d0531a595a3941f3f7409ce7044cb32ec9 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/07/98c93fd1e96d6b15821aa8753744620636cfd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/07/98c93fd1e96d6b15821aa8753744620636cfd1 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/2a/65dc2033ef649d8dd7e61a9ebb27a79d1291ac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/2a/65dc2033ef649d8dd7e61a9ebb27a79d1291ac -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/2f/49ad06a932c5b4a4cd646842582ac797ece30d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/2f/49ad06a932c5b4a4cd646842582ac797ece30d -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/39/e6bbff8dc4ac0973142faa7cfd39d211539a36: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/39/e6bbff8dc4ac0973142faa7cfd39d211539a36 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/4c/e114ad809cacceedde04f6c64b20417e153fd2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/4c/e114ad809cacceedde04f6c64b20417e153fd2 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/57/f9931e1d91ee5c034bd1d2b51ee73927c9a08f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/57/f9931e1d91ee5c034bd1d2b51ee73927c9a08f -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/65/2063eeeb250e50bc7c2ad6c661ab340fcb7d28: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/65/2063eeeb250e50bc7c2ad6c661ab340fcb7d28 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/7e/4c735d3464013cc11b0099b9320fd849e900df: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/7e/4c735d3464013cc11b0099b9320fd849e900df -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/85/c155f96fdb72d1a4936d56376edbe38c72f986: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/85/c155f96fdb72d1a4936d56376edbe38c72f986 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/ad/79b28f71daa47a2759b47511800457af0f0109: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/ad/79b28f71daa47a2759b47511800457af0f0109 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/b0/108ce3a7beec624243c91fe1989ed20fcc01b1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/b0/108ce3a7beec624243c91fe1989ed20fcc01b1 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/b9/7a03123ac2c017ce5918aa80eea113e019b9d3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/b9/7a03123ac2c017ce5918aa80eea113e019b9d3 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/c9/5cf571c583ff18ec1224ba4b26c2a3eec6881f: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/c9/5cf571c583ff18ec1224ba4b26c2a3eec6881f -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/d5/93a25337a23624a6c68a063ae613f9100e85f2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/d5/93a25337a23624a6c68a063ae613f9100e85f2 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/ed/56ae4bc0b05310eeeab2d46b04d51c293c6243: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/objects/ed/56ae4bc0b05310eeeab2d46b04d51c293c6243 -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/refs/tags/v1.0.0: -------------------------------------------------------------------------------- 1 | 7e4c735d3464013cc11b0099b9320fd849e900df 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/refs/tags/v1.0.1: -------------------------------------------------------------------------------- 1 | b97a03123ac2c017ce5918aa80eea113e019b9d3 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/refs/tags/v2.0.0: -------------------------------------------------------------------------------- 1 | 4ce114ad809cacceedde04f6c64b20417e153fd2 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/refs/tags/v2.0.1: -------------------------------------------------------------------------------- 1 | 0798c93fd1e96d6b15821aa8753744620636cfd1 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/refs/tags/v2.0.2: -------------------------------------------------------------------------------- 1 | b0108ce3a7beec624243c91fe1989ed20fcc01b1 2 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/cache/vcs/cb23a87db31f5113694f36f8e0fda5feaa943a461fc103a2cbb167f55742d572/shallow: -------------------------------------------------------------------------------- 1 | 7e4c735d3464013cc11b0099b9320fd849e900df 2 | b97a03123ac2c017ce5918aa80eea113e019b9d3 3 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod/v2@v2.0.2/README.md: -------------------------------------------------------------------------------- 1 | # testmod -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod/v2@v2.0.2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod/v2 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod/v2@v2.0.2/test.go: -------------------------------------------------------------------------------- 1 | package testmod 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Hello(name string, surname string) { 8 | fmt.Printf("Hello %s %s\n", name, surname) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.0/README.md: -------------------------------------------------------------------------------- 1 | # testmod -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.0/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.0/test.go: -------------------------------------------------------------------------------- 1 | package testmod 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Hello(name string) { 8 | fmt.Printf("Hello %s", name) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.1/README.md: -------------------------------------------------------------------------------- 1 | # testmod -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.1/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/example/pkg/mod/github.com/!b!h!y!c!h!i!k/testmod@v1.0.1/test.go: -------------------------------------------------------------------------------- 1 | package testmod 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Hello(name string) { 8 | fmt.Printf("Hello %s\n", name) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/example/src/calc/antisin.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | cali "calc/internal" 5 | ) 6 | 7 | func Antisin(x float64) float64 { 8 | return 1 / cali.Sin(x) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/example/src/calc/internal/internal.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | func Sin(x float64) float64 { 8 | return math.Sin(x) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/example/src/calc/mult.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | func Mult(args ...int) int { 4 | acc := 1 5 | for _, v := range args { 6 | acc *= v 7 | } 8 | 9 | return acc 10 | } 11 | -------------------------------------------------------------------------------- /09-packages/example/src/calc/sum.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | func Sum(args ...int) int { 4 | acc := 0 5 | for _, v := range args { 6 | acc += v 7 | } 8 | 9 | return acc 10 | } 11 | -------------------------------------------------------------------------------- /09-packages/example/src/ex/ex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "nousing" 5 | 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | fmt.Printf("hello world") 11 | } 12 | -------------------------------------------------------------------------------- /09-packages/example/src/math2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | c "calc" 7 | c2 "calc/internal" 8 | ) 9 | 10 | func main() { 11 | fmt.Printf("Hello calc: %f\n", c.Antisin(3.1)) 12 | fmt.Printf("Hello calc: %f\n", c2.Sin(3.1)) 13 | } 14 | -------------------------------------------------------------------------------- /09-packages/example/src/nousing/no.go: -------------------------------------------------------------------------------- 1 | package nousing 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Welcome() { 8 | fmt.Printf("Welcome!\n") 9 | } 10 | func init() { 11 | fmt.Printf("I am init\n") 12 | } 13 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65" 6 | name = "github.com/go-sql-driver/mysql" 7 | packages = ["."] 8 | pruneopts = "UT" 9 | revision = "72cd26f257d44c1114970e19afddcd812016007e" 10 | version = "v1.4.1" 11 | 12 | [[projects]] 13 | digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3" 14 | name = "google.golang.org/appengine" 15 | packages = ["cloudsql"] 16 | pruneopts = "UT" 17 | revision = "b2f4a3cf3c67576a2ee09e1fe62656a5086ce880" 18 | version = "v1.6.1" 19 | 20 | [solve-meta] 21 | analyzer-name = "dep" 22 | analyzer-version = 1 23 | input-imports = ["github.com/go-sql-driver/mysql"] 24 | solver-name = "gps-cdcl" 25 | solver-version = 1 26 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/go-sql-driver/mysql" 30 | version = "1.4.1" 31 | 32 | [prune] 33 | go-tests = true 34 | unused-packages = true 35 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | _ "github.com/go-sql-driver/mysql" 7 | ) 8 | 9 | func main() { 10 | db, err := sql.Open("mysql", "root:password@/testbase") 11 | if err != nil { 12 | panic(err) 13 | } 14 | defer db.Close() 15 | fmt.Printf("Hello world") 16 | } 17 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/github.com/go-sql-driver/mysql/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DS_Store? 3 | ._* 4 | .Spotlight-V100 5 | .Trashes 6 | Icon? 7 | ehthumbs.db 8 | Thumbs.db 9 | .idea 10 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/github.com/go-sql-driver/mysql/appengine.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build appengine 10 | 11 | package mysql 12 | 13 | import ( 14 | "google.golang.org/appengine/cloudsql" 15 | ) 16 | 17 | func init() { 18 | RegisterDial("cloudsql", cloudsql.Dial) 19 | } 20 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/github.com/go-sql-driver/mysql/result.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlResult struct { 12 | affectedRows int64 13 | insertId int64 14 | } 15 | 16 | func (res *mysqlResult) LastInsertId() (int64, error) { 17 | return res.insertId, nil 18 | } 19 | 20 | func (res *mysqlResult) RowsAffected() (int64, error) { 21 | return res.affectedRows, nil 22 | } 23 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/github.com/go-sql-driver/mysql/transaction.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlTx struct { 12 | mc *mysqlConn 13 | } 14 | 15 | func (tx *mysqlTx) Commit() (err error) { 16 | if tx.mc == nil || tx.mc.closed.IsSet() { 17 | return ErrInvalidConn 18 | } 19 | err = tx.mc.exec("COMMIT") 20 | tx.mc = nil 21 | return 22 | } 23 | 24 | func (tx *mysqlTx) Rollback() (err error) { 25 | if tx.mc == nil || tx.mc.closed.IsSet() { 26 | return ErrInvalidConn 27 | } 28 | err = tx.mc.exec("ROLLBACK") 29 | tx.mc = nil 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by the Apache 2.0 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build appengine 6 | 7 | package cloudsql 8 | 9 | import ( 10 | "net" 11 | 12 | "appengine/cloudsql" 13 | ) 14 | 15 | func connect(instance string) (net.Conn, error) { 16 | return cloudsql.Dial(instance) 17 | } 18 | -------------------------------------------------------------------------------- /09-packages/example/src/testsql/vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All rights reserved. 2 | // Use of this source code is governed by the Apache 2.0 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !appengine 6 | 7 | package cloudsql 8 | 9 | import ( 10 | "errors" 11 | "net" 12 | ) 13 | 14 | func connect(instance string) (net.Conn, error) { 15 | return nil, errors.New(`cloudsql: not supported in App Engine "flexible environment"`) 16 | } 17 | -------------------------------------------------------------------------------- /09-packages/testprog/go.mod: -------------------------------------------------------------------------------- 1 | module mod 2 | 3 | go 1.12 4 | 5 | require github.com/BHYCHIK/testmod/v2 v2.0.2 6 | -------------------------------------------------------------------------------- /09-packages/testprog/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BHYCHIK/testmod/v2 v2.0.2 h1:wzOgDwFT+LRyEveQAAdesosIfXzCSNcOKgzoDZC8E6M= 2 | github.com/BHYCHIK/testmod/v2 v2.0.2/go.mod h1:HMjSoZ6kYyJI27CMXmwQiohM79/muXHKgqCsZMXBmO0= 3 | -------------------------------------------------------------------------------- /09-packages/testprog/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/BHYCHIK/testmod/v2" 5 | ) 6 | 7 | func main() { 8 | testmod.Hello("Ivan", "Remen") 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/testprog/mod: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/09-packages/testprog/mod -------------------------------------------------------------------------------- /09-packages/testprog/vendor/github.com/BHYCHIK/testmod/v2/README.md: -------------------------------------------------------------------------------- 1 | # testmod -------------------------------------------------------------------------------- /09-packages/testprog/vendor/github.com/BHYCHIK/testmod/v2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BHYCHIK/testmod/v2 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /09-packages/testprog/vendor/github.com/BHYCHIK/testmod/v2/test.go: -------------------------------------------------------------------------------- 1 | package testmod 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Hello(name string, surname string) { 8 | fmt.Printf("Hello %s %s\n", name, surname) 9 | } 10 | -------------------------------------------------------------------------------- /09-packages/testprog/vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/BHYCHIK/testmod/v2 v2.0.2 2 | github.com/BHYCHIK/testmod/v2 3 | -------------------------------------------------------------------------------- /10-interfaces-p2/01-nil/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type I interface{ M() } 6 | 7 | type T struct{} 8 | 9 | func (T) M() {} 10 | 11 | func main() { 12 | var t *T 13 | if t == nil { 14 | fmt.Println("t is nil") 15 | } else { 16 | fmt.Println("t is not nil") 17 | } 18 | var i I = t 19 | if i == nil { 20 | fmt.Println("i is nil") 21 | } else { 22 | fmt.Println("i is not nil") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /10-interfaces-p2/02-limit-reader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | var r io.Reader 12 | 13 | r = strings.NewReader("hello") 14 | r = io.LimitReader(r, 4) 15 | 16 | if _, err := io.Copy(os.Stdout, r); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /10-interfaces-p2/03-type-assertion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var i interface{} = "hello" 7 | 8 | s := i.(string) 9 | fmt.Println(s) // hello 10 | 11 | s, ok := i.(string) // hello true 12 | fmt.Println(s, ok) 13 | 14 | r, ok := i.(fmt.Stringer) // false 15 | fmt.Println(r, ok) 16 | 17 | f, ok := i.(float64) // 0 false 18 | fmt.Println(f, ok) 19 | } 20 | -------------------------------------------------------------------------------- /10-interfaces-p2/04-type-switch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type I1 interface { 6 | M1() 7 | } 8 | 9 | type T1 struct{} 10 | 11 | func (T1) M1() {} 12 | 13 | type I2 interface { 14 | I1 15 | M2() 16 | } 17 | 18 | type T2 struct{} 19 | 20 | func (T2) M1() {} 21 | func (T2) M2() {} 22 | 23 | func main() { 24 | var v I1 25 | switch v.(type) { 26 | case T1: 27 | fmt.Println("T1") 28 | case T2: 29 | fmt.Println("T2") 30 | case nil: 31 | fmt.Println("nil") 32 | default: 33 | fmt.Println("default") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /10-interfaces-p2/05-privates/contract/contgract.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Contract interface { 4 | Sign() error 5 | cancel() error 6 | } 7 | -------------------------------------------------------------------------------- /10-interfaces-p2/05-privates/contract/int_impl.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | import "fmt" 4 | 5 | type ContractInternalImpl struct { 6 | } 7 | 8 | func (c *ContractInternalImpl) Sign() error { 9 | return nil 10 | } 11 | 12 | func (c *ContractInternalImpl) cancel() error { 13 | fmt.Println("Nobody can implement cancel outside the package") 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /10-interfaces-p2/05-privates/impl/ext_impl.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | type ContractExternalImpl struct { 4 | } 5 | 6 | func (c *ContractExternalImpl) Sign() error { 7 | return nil 8 | } 9 | 10 | func (c *ContractExternalImpl) cancel() error { 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /10-interfaces-p2/05-sort/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | type Person struct { 9 | Name string 10 | Age int 11 | } 12 | 13 | // ByAge implements sort.Interface for []Person based on the Age field. 14 | type ByAge []Person 15 | 16 | func (a ByAge) Len() int { return len(a) } 17 | func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 18 | func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age } 19 | 20 | func main() { 21 | people := []Person{ 22 | {"Bob", 31}, 23 | {"John", 42}, 24 | {"Michael", 17}, 25 | {"Jenny", 26}, 26 | } 27 | 28 | sort.Sort(ByAge(people)) 29 | fmt.Println(people) 30 | } 31 | -------------------------------------------------------------------------------- /10-interfaces-p2/06-refs/main_test.go: -------------------------------------------------------------------------------- 1 | package refs 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type A struct { 9 | F1 int 10 | } 11 | 12 | func TestIfaceRefs(t *testing.T) { 13 | a := A{F1: 42} 14 | aref := &a 15 | 16 | var i1, i2 any 17 | 18 | i1 = a 19 | i2 = aref 20 | 21 | a.F1 = 100500 22 | 23 | fmt.Println(a, i1, i2) // {100500} {42} &{100500} 24 | 25 | // i1: iface.data = copy 26 | // i2: iface.data = reference 27 | 28 | } 29 | -------------------------------------------------------------------------------- /10-interfaces-p2/example/main.go: -------------------------------------------------------------------------------- 1 | package example 2 | -------------------------------------------------------------------------------- /10-interfaces-p2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/10-interfaces-p2 2 | 3 | go 1.24 4 | -------------------------------------------------------------------------------- /12-sync-primitives-p1/race/go.mod: -------------------------------------------------------------------------------- 1 | module otus.ru/race 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /12-sync-primitives-p1/race/race.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | wg := sync.WaitGroup{} 10 | text := "" 11 | wg.Add(2) 12 | go func() { 13 | text = "hello world" 14 | wg.Done() 15 | }() 16 | go func() { 17 | fmt.Println(text) 18 | wg.Done() 19 | }() 20 | wg.Wait() 21 | } 22 | -------------------------------------------------------------------------------- /12-sync-primitives-p1/race_limit/go.mod: -------------------------------------------------------------------------------- 1 | module otus.ru/race_limit 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /12-sync-primitives-p1/race_limit/race_limit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func main() { 8 | for i := 0; i < 10000; i++ { 9 | go func() { 10 | time.Sleep(10 * time.Second) 11 | }() 12 | } 13 | time.Sleep(time.Second) 14 | } 15 | -------------------------------------------------------------------------------- /14-concurrency-patterns/1_adhoc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | data := []int{1, 2, 3, 4} 7 | 8 | loopData := func(handleData chan<- int) { 9 | defer close(handleData) 10 | for i := range data { 11 | handleData <- data[i] 12 | } 13 | } 14 | 15 | handleData := make(chan int) 16 | go loopData(handleData) 17 | 18 | for num := range handleData { 19 | fmt.Println(num) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /14-concurrency-patterns/2_lexical/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | chanOwner := func() <-chan int { 7 | results := make(chan int, 5) 8 | go func() { 9 | defer close(results) 10 | for i := 0; i <= 5; i++ { 11 | results <- i 12 | } 13 | }() 14 | return results 15 | } 16 | 17 | consumer := func(results <-chan int) { 18 | for result := range results { 19 | fmt.Printf("Received: %d\n", result) 20 | } 21 | fmt.Println("Done receiving!") 22 | } 23 | 24 | results := chanOwner() 25 | consumer(results) 26 | } 27 | -------------------------------------------------------------------------------- /14-concurrency-patterns/3_1_leak/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | doWork := func(strings <-chan string) <-chan struct{} { 10 | completed := make(chan struct{}) 11 | go func() { 12 | defer func() { 13 | fmt.Println("doWork exited.") 14 | close(completed) 15 | }() 16 | for s := range strings { 17 | fmt.Println(s) 18 | } 19 | }() 20 | return completed 21 | } 22 | 23 | doWork(nil) 24 | 25 | time.Sleep(time.Second * 5) 26 | fmt.Println("Done.") 27 | } 28 | -------------------------------------------------------------------------------- /14-concurrency-patterns/3_2_done_ch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | doWork := func(done <-chan struct{}, strings <-chan string) <-chan struct{} { 10 | terminated := make(chan struct{}) 11 | go func() { 12 | defer func() { 13 | fmt.Println("doWork exited.") 14 | close(terminated) 15 | }() 16 | for { 17 | select { 18 | case s := <-strings: 19 | fmt.Println(s) 20 | case <-done: 21 | return 22 | } 23 | } 24 | }() 25 | return terminated 26 | } 27 | 28 | done := make(chan struct{}) 29 | terminated := doWork(done, nil) 30 | 31 | go func() { 32 | time.Sleep(1 * time.Second) 33 | fmt.Println("Canceling doWork goroutine...") 34 | close(done) 35 | }() 36 | 37 | <-terminated 38 | fmt.Println("Done.") 39 | } 40 | -------------------------------------------------------------------------------- /14-concurrency-patterns/3_3_close_data_ch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | doWork := func(strings <-chan int) <-chan struct{} { 10 | terminated := make(chan struct{}) 11 | go func() { 12 | defer func() { 13 | fmt.Println("doWork exited.") 14 | close(terminated) 15 | }() 16 | 17 | for s := range strings { 18 | fmt.Println(s) 19 | } 20 | }() 21 | return terminated 22 | } 23 | 24 | data := make(chan int) 25 | terminated := doWork(data) 26 | 27 | go func() { 28 | for i := 0; i < 3; i++ { 29 | data <- i 30 | time.Sleep(1 * time.Second) 31 | } 32 | 33 | fmt.Println("Canceling doWork goroutine...") 34 | close(data) 35 | }() 36 | 37 | <-terminated 38 | fmt.Println("Done.") 39 | } 40 | -------------------------------------------------------------------------------- /14-concurrency-patterns/4_or_magic/or1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func or1(channels ...<-chan struct{}) <-chan struct{} { 4 | done := make(chan struct{}) 5 | 6 | go func() { 7 | defer close(done) 8 | for { 9 | for _, ch := range channels { 10 | select { 11 | case <-ch: 12 | return 13 | default: 14 | } 15 | } 16 | } 17 | }() 18 | 19 | return done 20 | } 21 | -------------------------------------------------------------------------------- /14-concurrency-patterns/5_1_handle_err_in_place/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | checkStatus := func(done <-chan struct{}, urls ...string) <-chan *http.Response { 11 | responses := make(chan *http.Response) 12 | go func() { 13 | defer close(responses) 14 | for _, url := range urls { 15 | resp, err := http.Get(url) 16 | if err != nil { 17 | log.Printf("error received: %s", err) 18 | continue 19 | } 20 | select { 21 | case <-done: 22 | return 23 | case responses <- resp: 24 | } 25 | } 26 | }() 27 | return responses 28 | } 29 | 30 | done := make(chan struct{}) 31 | defer close(done) 32 | 33 | urls := []string{"https://www.google.com", "https://badhost"} 34 | for response := range checkStatus(done, urls...) { 35 | fmt.Printf("Response: %v\n", response.Status) 36 | _ = response.Body.Close() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /14-concurrency-patterns/6_1_pipeline/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | multiply := func(values []int, multiplier int) []int { 7 | multipliedValues := make([]int, len(values)) 8 | for i, v := range values { 9 | multipliedValues[i] = v * multiplier 10 | } 11 | return multipliedValues 12 | } 13 | 14 | add := func(values []int, additive int) []int { 15 | addedValues := make([]int, len(values)) 16 | for i, v := range values { 17 | addedValues[i] = v + additive 18 | } 19 | return addedValues 20 | } 21 | 22 | ints := []int{1, 2, 3, 4} 23 | for _, v := range add(multiply(ints, 2), 1) { 24 | fmt.Println(v) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /14-concurrency-patterns/6_2_stage_constructor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type ( 6 | TransformFn func(v, k int) int 7 | Stage func(values []int) []int 8 | ) 9 | 10 | func main() { 11 | multiplier := func(v, k int) int { return v * k } 12 | adder := func(v, k int) int { return v + k } 13 | 14 | newStage := func(fn TransformFn, n int) Stage { 15 | return func(values []int) []int { 16 | result := make([]int, len(values)) 17 | for i, v := range values { 18 | result[i] = fn(v, n) 19 | } 20 | return result 21 | } 22 | } 23 | 24 | multiply := newStage(multiplier, 2) 25 | add := newStage(adder, 1) 26 | 27 | ints := []int{1, 2, 3, 4} 28 | for _, v := range add(multiply(ints)) { 29 | fmt.Println(v) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_1_prime_finding/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | randFn := func() interface{} { return rand.Intn(100000000) } 11 | 12 | done := make(chan struct{}) 13 | defer close(done) 14 | 15 | start := time.Now() 16 | 17 | randIntStream := toInt(done, repeatFn(done, randFn)) 18 | fmt.Println("Primes:") 19 | for prime := range take(done, primeFinder(done, randIntStream), 10) { 20 | fmt.Printf("\t%d\n", prime) 21 | } 22 | 23 | fmt.Printf("Search took: %v", time.Since(start)) // ~10s 24 | } 25 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_1_prime_finding/prime_finder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan interface{} { 4 | primeStream := make(chan interface{}) 5 | go func() { 6 | defer close(primeStream) 7 | for v := range intStream { 8 | select { 9 | case <-done: 10 | return 11 | default: 12 | if isPrime(v) { 13 | select { 14 | case <-done: 15 | return 16 | case primeStream <- v: 17 | } 18 | } 19 | } 20 | } 21 | }() 22 | return primeStream 23 | } 24 | 25 | // Very slow calculation. 26 | func isPrime(v int) bool { 27 | for i := 2; i < v-1; i++ { 28 | if v%i == 0 { 29 | return false 30 | } 31 | } 32 | return true 33 | } 34 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_1_prime_finding/repeat_fn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func repeatFn(done <-chan struct{}, fn func() interface{}) <-chan interface{} { 4 | valueStream := make(chan interface{}) 5 | go func() { 6 | defer close(valueStream) 7 | for { 8 | select { 9 | case <-done: 10 | return 11 | case valueStream <- fn(): 12 | } 13 | } 14 | }() 15 | return valueStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_1_prime_finding/take.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func take(done <-chan struct{}, valueStream <-chan interface{}, num int) <-chan interface{} { 4 | takeStream := make(chan interface{}) 5 | go func() { 6 | defer close(takeStream) 7 | for i := 0; i < num; i++ { 8 | select { 9 | case <-done: 10 | return 11 | case takeStream <- <-valueStream: 12 | } 13 | } 14 | }() 15 | return takeStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_1_prime_finding/to_int.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func toInt(done <-chan struct{}, valueStream <-chan interface{}) <-chan int { 4 | intStream := make(chan int) 5 | go func() { 6 | defer close(intStream) 7 | for v := range valueStream { 8 | select { 9 | case <-done: 10 | return 11 | case intStream <- v.(int): 12 | } 13 | } 14 | }() 15 | return intStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_2_fanin_fanout/fan_in.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | func fanIn(done <-chan struct{}, channels ...<-chan interface{}) <-chan interface{} { 6 | var wg sync.WaitGroup 7 | multiplexedStream := make(chan interface{}) 8 | multiplex := func(c <-chan interface{}) { 9 | defer wg.Done() 10 | for i := range c { 11 | select { 12 | case <-done: 13 | return 14 | case multiplexedStream <- i: 15 | } 16 | } 17 | } 18 | 19 | // Select from all the channels. 20 | wg.Add(len(channels)) 21 | for _, c := range channels { 22 | go multiplex(c) 23 | } 24 | 25 | // Wait for all the reads to complete. 26 | go func() { 27 | wg.Wait() 28 | close(multiplexedStream) 29 | }() 30 | 31 | return multiplexedStream 32 | } 33 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_2_fanin_fanout/prime_finder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func primeFinder(done <-chan struct{}, intStream <-chan int) <-chan interface{} { 4 | primeStream := make(chan interface{}) 5 | go func() { 6 | defer close(primeStream) 7 | for v := range intStream { 8 | select { 9 | case <-done: 10 | return 11 | default: 12 | if isPrime(v) { 13 | select { 14 | case <-done: 15 | return 16 | case primeStream <- v: 17 | } 18 | } 19 | } 20 | } 21 | }() 22 | return primeStream 23 | } 24 | 25 | // Very slow calculation. 26 | func isPrime(v int) bool { 27 | for i := 2; i < v-1; i++ { 28 | if v%i == 0 { 29 | return false 30 | } 31 | } 32 | return true 33 | } 34 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_2_fanin_fanout/repeat_fn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func repeatFn(done <-chan struct{}, fn func() interface{}) <-chan interface{} { 4 | valueStream := make(chan interface{}) 5 | go func() { 6 | defer close(valueStream) 7 | for { 8 | select { 9 | case <-done: 10 | return 11 | case valueStream <- fn(): 12 | } 13 | } 14 | }() 15 | return valueStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_2_fanin_fanout/take.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func take(done <-chan struct{}, valueStream <-chan interface{}, num int) <-chan interface{} { 4 | takeStream := make(chan interface{}) 5 | go func() { 6 | defer close(takeStream) 7 | for i := 0; i < num; i++ { 8 | select { 9 | case <-done: 10 | return 11 | case takeStream <- <-valueStream: 12 | } 13 | } 14 | }() 15 | return takeStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/9_2_fanin_fanout/to_int.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func toInt(done <-chan struct{}, valueStream <-chan interface{}) <-chan int { 4 | intStream := make(chan int) 5 | go func() { 6 | defer close(intStream) 7 | for v := range valueStream { 8 | select { 9 | case <-done: 10 | return 11 | case intStream <- v.(int): 12 | } 13 | } 14 | }() 15 | return intStream 16 | } 17 | -------------------------------------------------------------------------------- /14-concurrency-patterns/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/14-concurrency-patterns 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /16-internals-memory/halfsum/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //go:noinline 6 | func HalfSum(a, b int) int { 7 | c := a + b 8 | c /= 2 9 | return c 10 | } 11 | 12 | // go tool compile -S main.go 13 | // go tool compile -m main.go 14 | func main() { 15 | s := HalfSum(1, 2) 16 | fmt.Println(s) 17 | } 18 | -------------------------------------------------------------------------------- /16-internals-memory/heap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | n := answer() 5 | println(*n) 6 | } 7 | 8 | //go:noinline 9 | func answer() *int { 10 | x := 42 11 | return &x 12 | } 13 | -------------------------------------------------------------------------------- /16-internals-memory/stack/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | n := 4 5 | n2 := square(n) 6 | println(n2) 7 | } 8 | 9 | //go:noinline 10 | func square(x int) int { 11 | return x * x 12 | } 13 | -------------------------------------------------------------------------------- /16-internals-memory/stack_pointer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | n := 4 5 | square(&n) 6 | println(n) 7 | } 8 | 9 | //go:noinline 10 | func square(x *int) { 11 | *x = (*x) * (*x) 12 | } 13 | -------------------------------------------------------------------------------- /17-input-output/exampletest/example_test.go: -------------------------------------------------------------------------------- 1 | package exampletest_test 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestReadFile(t *testing.T) { 12 | f, err := os.Open("testdata/example.txt") 13 | require.NoError(t, err) 14 | 15 | defer func() { 16 | require.NoError(t, f.Close()) 17 | }() 18 | 19 | b, err := io.ReadAll(f) 20 | require.NoError(t, err) 21 | 22 | t.Log(string(b)) 23 | } 24 | -------------------------------------------------------------------------------- /17-input-output/exampletest/testdata/example.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /17-input-output/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/17-input-output 2 | 3 | go 1.16 4 | 5 | require github.com/stretchr/testify v1.7.0 // indirect 6 | -------------------------------------------------------------------------------- /17-input-output/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 7 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /17-input-output/regex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | func main() { 9 | 10 | // Определите шаблон регулярного выражения с подвыражениями 11 | pattern := regexp.MustCompile(`(\w+)-(\d+)`) 12 | 13 | // Входная строка для сопоставления 14 | input := "example-123" 15 | 16 | // Найти подвыражения во входной строке 17 | subMatches := pattern.FindStringSubmatch(input) 18 | 19 | // Проверить, есть ли совпадение 20 | if len(subMatches) > 0 { 21 | // Первый элемент - это полное совпадение, следующие элементы - подвыражения 22 | fmt.Println("Полное совпадение:", subMatches[0]) 23 | fmt.Println("Первое подвыражение:", subMatches[1]) 24 | fmt.Println("Второе подвыражение:", subMatches[2]) 25 | } else { 26 | fmt.Println("Совпадений не найдено") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /17-input-output/writefile/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | func main() { 8 | file, err := os.Create("/tmp/fff") 9 | if err != nil { 10 | panic(err) 11 | } 12 | 13 | b := make([]byte, 1<<20) 14 | _, err = file.Write(b) 15 | if err != nil { 16 | panic(err) 17 | } 18 | if err := file.Close(); err != nil { 19 | panic(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /17-reflection/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/magiconair/properties/assert" 8 | ) 9 | 10 | func TestSetFail(t *testing.T) { 11 | v := 5.5 12 | rVal := reflect.ValueOf(v) 13 | assert.Panic(t, func() { 14 | rVal.SetFloat(1.1) 15 | }, "") 16 | 17 | t.Log(v) 18 | } 19 | 20 | func TestSetOk(t *testing.T) { 21 | v := 5.5 22 | rVal := reflect.ValueOf(&v) 23 | t.Log(rVal.String(), rVal) 24 | 25 | rVal.Elem().SetFloat(1.1) 26 | 27 | t.Log(v) 28 | } 29 | -------------------------------------------------------------------------------- /18-format/base64/base64.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | b64 "encoding/base64" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | data := "Hello world" 10 | 11 | sEnc := b64.StdEncoding.EncodeToString([]byte(data)) 12 | fmt.Println(sEnc) 13 | 14 | sDec, err := b64.StdEncoding.DecodeString(sEnc) 15 | mustNil(err) 16 | fmt.Println(string(sDec)) 17 | fmt.Println() 18 | 19 | uEnc := b64.URLEncoding.EncodeToString([]byte(data)) 20 | fmt.Println(uEnc) 21 | 22 | uDec, err := b64.URLEncoding.DecodeString(uEnc) 23 | mustNil(err) 24 | fmt.Println(string(uDec)) 25 | fmt.Println() 26 | } 27 | 28 | func mustNil(err error) { 29 | if err != nil { 30 | panic(err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /18-format/base64flow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "io" 7 | "os" 8 | ) 9 | 10 | type Printer struct { 11 | r *io.PipeReader 12 | w *io.PipeWriter 13 | } 14 | 15 | func (p Printer) Read(d []byte) (n int, err error) { 16 | return p.r.Read(d) 17 | } 18 | 19 | func (p Printer) Write(d []byte) (n int, err error) { 20 | fmt.Println(string(d)) 21 | return p.w.Write(d) 22 | } 23 | 24 | func main() { 25 | r, w := io.Pipe() 26 | p := Printer{r, w} 27 | 28 | encoder := base64.NewEncoder(base64.StdEncoding, p) 29 | defer func() { mustNil(encoder.Close()) }() 30 | 31 | go io.Copy(encoder, os.Stdin) 32 | 33 | decoder := base64.NewDecoder(base64.StdEncoding, p) 34 | io.Copy(os.Stdout, decoder) 35 | } 36 | 37 | func mustNil(err error) { 38 | if err != nil { 39 | panic(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /18-format/jsonex/0_json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type Person struct { 10 | Name string 11 | age int 12 | Job struct { 13 | Department string 14 | Title string 15 | } 16 | Phones []string // Как сделать [] вместо null? 17 | } 18 | 19 | func main() { 20 | p1 := &Person{ 21 | Name: "Vasya", 22 | age: 36, 23 | Job: struct { 24 | Department string 25 | Title string 26 | }{Department: "Operations", Title: "Boss"}, 27 | } 28 | 29 | j, err := json.MarshalIndent(p1, "--", " ") 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | fmt.Printf("p1 json %s\n", j) 34 | 35 | j, err = json.Marshal(p1) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | fmt.Printf("p1 json %s\n", j) 40 | 41 | var p2 Person 42 | if err := json.Unmarshal(j, &p2); err != nil { 43 | log.Fatal(err) 44 | } 45 | fmt.Printf("p2: %v\n", p2) 46 | } 47 | 48 | // Как валидировать? 49 | -------------------------------------------------------------------------------- /18-format/jsonex/1_json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | func main() { 10 | j := []byte(`{"Name":"Vasya", 11 | "Job":{"Department":"Operations","Title":"Boss"}}`) 12 | 13 | var p2 interface{} 14 | if err := json.Unmarshal(j, &p2); err != nil { 15 | log.Fatal(err) 16 | } 17 | fmt.Printf("p2: %v\n", p2) 18 | 19 | person := p2.(map[string]interface{}) 20 | fmt.Printf("name=%s\n", person["Name"]) 21 | } 22 | -------------------------------------------------------------------------------- /18-format/jsonex/2_json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type Person struct { 10 | Name string `json:"fullname, omitempty"` 11 | Surname string `json:"familyname, omitempty"` 12 | Age int `json:"-"` 13 | Job struct { 14 | Department string 15 | Title string 16 | } 17 | } 18 | 19 | func main() { 20 | p1 := &Person{ 21 | Name: "Vasya", 22 | Surname: "Petrov", 23 | Age: 36, 24 | Job: struct { 25 | Department string 26 | Title string 27 | }{Department: "Operations", Title: "Boss"}, 28 | } 29 | 30 | j, err := json.Marshal(p1) 31 | if err != nil { 32 | fmt.Printf("%v\n", err) 33 | return 34 | } 35 | fmt.Printf("p1 json %s\n", j) 36 | 37 | var p2 Person 38 | if err := json.Unmarshal(j, &p2); err != nil { 39 | log.Fatal(err) 40 | } 41 | fmt.Printf("p2: %v\n", p2) 42 | } 43 | -------------------------------------------------------------------------------- /18-format/jsonex/3_different_rules.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type Person struct { 10 | Name string 11 | Age int 12 | } 13 | 14 | func main() { 15 | var p Person 16 | if err := json.Unmarshal([]byte(`{"Name": "Vasya", "Age": 32}`), &p); err != nil { 17 | log.Fatal(err) 18 | } 19 | 20 | data, err := json.Marshal(p) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | fmt.Println(string(data)) 25 | } 26 | -------------------------------------------------------------------------------- /18-format/jsonex/4_recursive_problem.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type Person struct { 10 | Name string 11 | Age int 12 | } 13 | 14 | func (p Person) MarshalJSON() ([]byte, error) { 15 | fmt.Println(p.Name + " is cool in marshaling") 16 | return json.Marshal(p) 17 | } 18 | 19 | func (p *Person) UnmarshalJSON(data []byte) error { 20 | fmt.Println(p.Name + " is cool in unmarshaling") 21 | return json.Unmarshal(data, p) 22 | } 23 | 24 | func main() { 25 | var p Person 26 | if err := json.Unmarshal([]byte(`{"Name": "Vasya", "Age": 32}`), &p); err != nil { 27 | log.Fatal(err) 28 | } 29 | 30 | data, err := json.Marshal(p) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | fmt.Println(string(data)) 35 | } 36 | -------------------------------------------------------------------------------- /18-format/jsonex/5_raw_message.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type Person struct { 10 | Name string 11 | Age int 12 | Meta json.RawMessage 13 | } 14 | 15 | func main() { 16 | data, err := json.Marshal(Person{ 17 | Name: "Vasya", 18 | Age: 32, 19 | Meta: json.RawMessage(`{"settings": {}}`), 20 | }) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | fmt.Println(string(data)) 25 | } 26 | -------------------------------------------------------------------------------- /18-format/msgpackex/ex1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/vmihailenco/msgpack" 8 | ) 9 | 10 | type Person struct { 11 | Name string 12 | Surname string 13 | Age uint32 14 | ChildrenAge map[string]uint32 15 | } 16 | 17 | func main() { 18 | p := Person{ 19 | Name: "Ivan", 20 | Surname: "Remen", 21 | Age: 27, 22 | } 23 | p.ChildrenAge = make(map[string]uint32) 24 | p.ChildrenAge["Alex"] = 5 25 | p.ChildrenAge["Maria"] = 2 26 | 27 | marshaled, err := msgpack.Marshal(&p) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | fmt.Printf("\nLength of marshaled: %v IMPL: %v\n", len(marshaled), string(marshaled)) 33 | 34 | p2 := &Person{} 35 | if err := msgpack.Unmarshal(marshaled, p2); err != nil { 36 | log.Fatal(err) 37 | } 38 | fmt.Printf("Unmarshled: %v\n", p2) 39 | } 40 | -------------------------------------------------------------------------------- /18-format/protobufex/gen.sh: -------------------------------------------------------------------------------- 1 | protoc --go_out=. *.proto 2 | -------------------------------------------------------------------------------- /18-format/protobufex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "google.golang.org/protobuf/proto" 8 | ) 9 | 10 | func main() { 11 | p := &Person{ 12 | Age: 27, 13 | Name: "Ivan", 14 | Surname: "Remen", 15 | ChildrenAge: make(map[string]uint32), 16 | } 17 | p.ChildrenAge["Maria"] = 2 18 | p.ChildrenAge["Alex"] = 5 19 | 20 | marshaled, err := proto.Marshal(p) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | 25 | fmt.Printf("marshaled len %d message = %s\n", len(marshaled), string(marshaled)) 26 | fmt.Println(marshaled) 27 | 28 | p2 := &Person{} 29 | if err := proto.Unmarshal(marshaled, p2); err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | fmt.Printf("\nUnmarshaled %v", p2) 34 | } 35 | -------------------------------------------------------------------------------- /18-format/protobufex/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package main; 4 | option go_package = ".;main"; 5 | 6 | message Person { 7 | string name = 1; 8 | string surname = 2; 9 | uint32 age = 3; 10 | 11 | map children_age = 4; 12 | } 13 | -------------------------------------------------------------------------------- /18-format/xmlex/xml1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/xml" 5 | "log" 6 | "os" 7 | ) 8 | 9 | type Address struct { 10 | City, State string 11 | } 12 | 13 | type Person struct { 14 | XMLName xml.Name `xml:"person"` 15 | Id int `xml:"id,attr"` 16 | FirstName string `xml:"name>first"` 17 | LastName string `xml:"name>last"` 18 | Age int `xml:"age"` 19 | Height float32 `xml:"height,omitempty"` 20 | Married bool 21 | Address 22 | Comment string `xml:",comment"` 23 | } 24 | 25 | func main() { 26 | v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} 27 | v.Comment = " Need more details. " 28 | v.Address = Address{"Hanga Roa", "Easter Island"} 29 | 30 | enc := xml.NewEncoder(os.Stdout) 31 | enc.Indent(" ", " ") 32 | if err := enc.Encode(v); err != nil { 33 | log.Fatal(err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /19-clean-architecture/.gitignore: -------------------------------------------------------------------------------- 1 | clncnd 2 | -------------------------------------------------------------------------------- /19-clean-architecture/Makefile: -------------------------------------------------------------------------------- 1 | gen: 2 | protoc --go_out=plugins=grpc:internal/adapters/grpc api/*.proto 3 | 4 | lint: 5 | golangci-lint run ./... 6 | 7 | build: gen 8 | go build -o clncnd main.go 9 | -------------------------------------------------------------------------------- /19-clean-architecture/api/api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "google/protobuf/timestamp.proto"; 4 | 5 | message Event { 6 | string id = 1; 7 | string title = 2; 8 | string text = 3; 9 | string owner = 4; 10 | google.protobuf.Timestamp start_time = 5; 11 | google.protobuf.Timestamp end_time = 6; 12 | } 13 | 14 | message CreateEventRequest { 15 | string title = 1; 16 | string text = 2; 17 | google.protobuf.Timestamp start_time = 3; 18 | google.protobuf.Timestamp end_time = 4; 19 | } 20 | 21 | message CreateEventResponse { 22 | oneof result { 23 | Event event = 1; 24 | string error = 2; 25 | } 26 | } 27 | 28 | service CalendarService { 29 | rpc CreateEvent(CreateEventRequest) returns (CreateEventResponse) {} 30 | } 31 | -------------------------------------------------------------------------------- /19-clean-architecture/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | var RootCmd = &cobra.Command{ 8 | Use: "clncnd", 9 | Short: "CleanCalendar is a calendar micorservice demo", 10 | } 11 | 12 | func init() { 13 | RootCmd.AddCommand(GrpcServerCmd) 14 | RootCmd.AddCommand(GrpcClientCmd) 15 | } 16 | -------------------------------------------------------------------------------- /19-clean-architecture/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/19-clean-architecture 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cockroachdb/apd v1.1.0 // indirect 7 | github.com/gofrs/uuid v4.0.0+incompatible // indirect 8 | github.com/golang/protobuf v1.5.2 9 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect 10 | github.com/jackc/pgx v3.6.2+incompatible 11 | github.com/jmoiron/sqlx v1.3.3 12 | github.com/pkg/errors v0.9.1 // indirect 13 | github.com/satori/go.uuid v1.2.0 14 | github.com/shopspring/decimal v0.0.0-20190905144223-a36b5d85f337 // indirect 15 | github.com/spf13/cobra v1.1.3 16 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect 17 | golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect 18 | golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect 19 | google.golang.org/genproto v0.0.0-20210426193834-eac7f76ac494 // indirect 20 | google.golang.org/grpc v1.37.0 21 | ) 22 | -------------------------------------------------------------------------------- /19-clean-architecture/internal/domain/entities/event.go: -------------------------------------------------------------------------------- 1 | package entities 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/satori/go.uuid" 7 | ) 8 | 9 | type Event struct { 10 | ID uuid.UUID 11 | Owner string 12 | Title string 13 | Text string 14 | StartTime *time.Time 15 | EndTime *time.Time 16 | } 17 | -------------------------------------------------------------------------------- /19-clean-architecture/internal/domain/errors/error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | type EventError string 4 | 5 | func (ee EventError) Error() string { 6 | return string(ee) 7 | } 8 | 9 | var ( 10 | ErrOverlaping = EventError("another event exists for this date") 11 | ErrIncorrectEndDate = EventError("end_date is incorrect") 12 | ) 13 | -------------------------------------------------------------------------------- /19-clean-architecture/internal/domain/interfaces/event_storage.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/OtusGolang/webinars_practical_part/19-clean-architecture/internal/domain/entities" 8 | ) 9 | 10 | type EventStorage interface { 11 | SaveEvent(ctx context.Context, event *entities.Event) error 12 | GetEventByID(ctx context.Context, id string) (*entities.Event, error) 13 | GetEventsByOwnerStartDate(ctx context.Context, owner string, startTime time.Time) ([]entities.Event, error) 14 | } 15 | -------------------------------------------------------------------------------- /19-clean-architecture/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/OtusGolang/webinars_practical_part/19-clean-architecture/cmd" 7 | ) 8 | 9 | func main() { 10 | if err := cmd.RootCmd.Execute(); err != nil { 11 | log.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /19-clean-architecture/sql/001.sql: -------------------------------------------------------------------------------- 1 | create table events ( 2 | id UUID primary key, 3 | owner text not null, 4 | title text not null, 5 | text text, 6 | start_time timestamp not null, 7 | end_time timestamp 8 | ) 9 | -------------------------------------------------------------------------------- /19-clean-architecture/sql/002.sql: -------------------------------------------------------------------------------- 1 | CREATE INDEX owner_start_time_idx ON events USING btree (owner, start_time); 2 | -------------------------------------------------------------------------------- /19-os/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "os/exec" 7 | ) 8 | 9 | func main() { 10 | cmd := exec.Command("../env/env") 11 | cmd.Env = append(os.Environ(), 12 | "USER=petya", 13 | "CITY=Msk", 14 | ) 15 | 16 | if err := cmd.Run(); err != nil { 17 | log.Fatal(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /19-os/cmd_pipe/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "os/exec" 7 | ) 8 | 9 | func main() { 10 | lsCmd := exec.Command("ls") 11 | wcCmd := exec.Command("wc", "-l") 12 | 13 | pipe, _ := lsCmd.StdoutPipe() 14 | wcCmd.Stdin = pipe 15 | wcCmd.Stdout = os.Stdout 16 | 17 | log.Println("ls start err:", lsCmd.Start()) 18 | log.Println("wc start err:", wcCmd.Start()) 19 | log.Println("ls wait err:", lsCmd.Wait()) 20 | log.Println("wc wait err:", wcCmd.Wait()) 21 | } 22 | -------------------------------------------------------------------------------- /19-os/cobra/git2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/otus/git2 2 | 3 | go 1.14 4 | 5 | require github.com/spf13/cobra v1.1.3 6 | -------------------------------------------------------------------------------- /19-os/cobra/git2/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2020 NAME HERE 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 | package main 17 | 18 | import "github.com/otus/git2/cmd" 19 | 20 | func main() { 21 | cmd.Execute() 22 | } 23 | -------------------------------------------------------------------------------- /19-os/env/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | env := os.Environ() // слайс строк "key=value" 10 | fmt.Println(env[0]) // USER=rob 11 | 12 | user, ok := os.LookupEnv("USER") 13 | fmt.Println(user, ok) // rob 14 | 15 | os.Setenv("PASSWORD", "qwe123") // установить 16 | os.Unsetenv("PASSWORD") // удалить 17 | fmt.Println(os.ExpandEnv("$USER lives in ${CITY}")) // "шаблонизация" 18 | } 19 | -------------------------------------------------------------------------------- /19-os/flag/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | var msg string 10 | 11 | verbose := flag.Bool("verbose", false, "verbose output") 12 | flag.StringVar(&msg, "msg", "hello", "message to print") 13 | 14 | flag.Parse() 15 | 16 | if *verbose { 17 | fmt.Println("you say:", msg) 18 | } else { 19 | fmt.Println(msg) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /19-os/go.mod: -------------------------------------------------------------------------------- 1 | module example.com/otus-os 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 7 | github.com/spf13/pflag v1.0.5 8 | ) 9 | -------------------------------------------------------------------------------- /19-os/go.sum: -------------------------------------------------------------------------------- 1 | github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 h1:3T8ZyTDp5QxTx3NU48JVb2u+75xc040fofcBaN+6jPA= 2 | github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185/go.mod h1:cFRxtTwTOJkz2x3rQUNCYKWC93yP1VKjR8NUhqFxZNU= 3 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 4 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 5 | -------------------------------------------------------------------------------- /19-os/pflag/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/pflag" 7 | ) 8 | 9 | func main() { 10 | var msg string 11 | 12 | verbose := pflag.BoolP("verbose", "v", false, "verbose output") 13 | pflag.StringVarP(&msg, "msg", "m", "hello", "message to print") 14 | // pflag.Lookup("msg").NoOptDefVal = "bye" 15 | 16 | pflag.Parse() 17 | 18 | if *verbose { 19 | fmt.Println("you say:", msg) 20 | } else { 21 | fmt.Println(msg) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /19-os/safefile/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | 8 | "github.com/dchest/safefile" 9 | ) 10 | 11 | func main() { 12 | tmpfile, err := safefile.Create("/tmp/example.txt", 0644) 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | fmt.Println(tmpfile.Name()) 17 | defer tmpfile.Close() 18 | 19 | content := []byte("temporary file's content\n") 20 | if _, err := tmpfile.Write(content); err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | time.Sleep(10 * time.Second) 25 | 26 | fmt.Println("commit") 27 | if err := tmpfile.Commit(); err != nil { 28 | log.Fatal(err) 29 | } 30 | time.Sleep(10 * time.Second) 31 | } 32 | -------------------------------------------------------------------------------- /19-os/signal/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | ) 9 | 10 | func main() { 11 | fmt.Println("pid:", os.Getpid()) 12 | 13 | c := make(chan os.Signal, 1) 14 | signal.Notify(c, syscall.SIGINT, syscall.SIGKILL) 15 | signal.Ignore(syscall.SIGTERM) 16 | 17 | for s := range c { 18 | fmt.Println("Got signal:", s) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /19-os/tmpfiles/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | tmpfile, err := os.CreateTemp("/tmp", "example.") 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | fmt.Println(tmpfile.Name()) 15 | defer os.Remove(tmpfile.Name()) 16 | 17 | content := []byte("temporary file's content\n") 18 | if _, err := tmpfile.Write(content); err != nil { 19 | log.Fatal(err) 20 | } 21 | 22 | if err := tmpfile.Close(); err != nil { 23 | log.Fatal(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /20-reflection/1_value/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | i := 42 10 | s := struct { 11 | string 12 | int 13 | }{"hello", 42} 14 | 15 | iv := reflect.ValueOf(i) 16 | sv := reflect.ValueOf(&s) 17 | 18 | fmt.Printf("%T: %v\n", iv, iv) 19 | fmt.Printf("%T: %v\n", sv, sv) 20 | } 21 | -------------------------------------------------------------------------------- /20-reflection/2_assert_string/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func assertString(iv interface{}) (string, bool) { 9 | rv := reflect.ValueOf(iv) 10 | var s string 11 | var ok bool 12 | if rv.Kind() == reflect.String { 13 | s = rv.String() 14 | ok = true 15 | } 16 | return s, ok 17 | } 18 | 19 | func main() { 20 | var iv interface{} = "hello" 21 | s, ok := assertString(iv) 22 | fmt.Printf("%q %v\n", s, ok) 23 | 24 | s2, ok := assertString(42) 25 | fmt.Printf("%q %v\n", s2, ok) 26 | } 27 | -------------------------------------------------------------------------------- /20-reflection/3_set_value/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | x := 3. 10 | 11 | p := reflect.ValueOf(x) 12 | fmt.Println(p.Type(), ":", p.CanSet()) // ? 13 | 14 | p = reflect.ValueOf(&x) 15 | fmt.Println(p.Type(), ":", p.CanSet()) // ? 16 | 17 | v := p.Elem() 18 | fmt.Println(v.Type(), ":", v.CanSet()) // ? 19 | 20 | v.SetFloat(7.1) 21 | fmt.Println(x) 22 | } 23 | -------------------------------------------------------------------------------- /20-reflection/4_struct_to_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/OtusGolang/webinars_practical_part/20-reflection/user" 8 | ) 9 | 10 | type Student struct { 11 | Name string 12 | Age int 13 | } 14 | 15 | func structToMap(iv interface{}) (map[string]interface{}, error) { 16 | v := reflect.ValueOf(iv) 17 | if v.Kind() != reflect.Struct { 18 | return nil, fmt.Errorf("expected a struct, but received %T", iv) 19 | } 20 | 21 | t := v.Type() 22 | mp := make(map[string]interface{}, t.NumField()) 23 | for i := 0; i < t.NumField(); i++ { 24 | field := t.Field(i) // reflect.StructField 25 | fv := v.Field(i) // reflect.Value 26 | if fv.CanInterface() { 27 | mp[field.Name] = fv.Interface() 28 | } 29 | } 30 | return mp, nil 31 | } 32 | 33 | func main() { 34 | st := Student{"Bob", 18} 35 | mp, err := structToMap(st) 36 | fmt.Printf("MAP: %#v\nERR: %s\n", mp, err) 37 | 38 | st1, err := structToMap(user.User{Name: "Alex", Age: 100}) 39 | fmt.Println(st1, err) 40 | } 41 | -------------------------------------------------------------------------------- /20-reflection/6_method_list/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Int int 9 | 10 | func (i Int) Say() string { 11 | return "42" 12 | } 13 | 14 | func (i Int) Say50() string { 15 | return "50" 16 | } 17 | 18 | func main() { 19 | var obj Int 20 | v := reflect.ValueOf(obj) 21 | for i := 0; i < v.NumMethod(); i++ { 22 | method := v.Method(i) // reflect.Value 23 | fmt.Println(v.Type().Method(i).Name, method) 24 | } 25 | 26 | sayMethod := v.MethodByName("Say") // reflect.Value 27 | fmt.Println(sayMethod.Call(nil)) 28 | } 29 | -------------------------------------------------------------------------------- /20-reflection/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/20-reflection 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /20-reflection/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | type User struct { 4 | Name string 5 | Age int 6 | privateField string 7 | } 8 | -------------------------------------------------------------------------------- /21-codegen/00-simple/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Hello, world!" 3 | -------------------------------------------------------------------------------- /21-codegen/00-simple/command.win.bat: -------------------------------------------------------------------------------- 1 | echo "Hello, world!" 2 | -------------------------------------------------------------------------------- /21-codegen/00-simple/example/example.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | //go:generate bye 4 | -------------------------------------------------------------------------------- /21-codegen/00-simple/generate.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package main 5 | 6 | import ( 7 | "log" 8 | "os" 9 | ) 10 | 11 | const helloFunc = `package main 12 | 13 | import "fmt" 14 | 15 | func Hello() { 16 | fmt.Println("Hello world!") 17 | } 18 | ` 19 | 20 | func main() { 21 | f, err := os.OpenFile("code.go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | defer f.Close() 26 | 27 | _, err = f.WriteString(helloFunc) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /21-codegen/00-simple/main.go: -------------------------------------------------------------------------------- 1 | //go:generate ./command.sh 2 | // FOR WINDOWS: //go:generate cmd /C command.win.bat 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | func main() { 9 | fmt.Println("run any unix command in go:generate") 10 | } 11 | 12 | //go:generate -command list ls -l 13 | //go:generate -command bye echo "Goodbye, world!" 14 | 15 | //go:generate bye 16 | //go:generate list 17 | //go:generate go run generate.go 18 | 19 | //go:generate echo f=$GOFILE p=$GOPACKAGE r=$GOROOT a=$GOARCH o=$GOOS d=$DOLLAR l=$GOLINE 20 | // Список: https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source 21 | 22 | //go:generate pwd 23 | 24 | // go generate 25 | // go generate -v 26 | // go generate -x 27 | // go generate -n 28 | // go generate -run bye 29 | -------------------------------------------------------------------------------- /21-codegen/01-bindata/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | type Handler struct { 9 | } 10 | 11 | func (*Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 12 | data, err := Asset("static/gopher.png") 13 | if err != nil { 14 | fmt.Printf("%v\n", err) 15 | w.WriteHeader(http.StatusInternalServerError) 16 | return 17 | } 18 | 19 | w.Header().Set("Content-Type", "image/png") 20 | w.Write(data) 21 | } 22 | 23 | func main() { 24 | if err := http.ListenAndServe(":8081", new(Handler)); err != nil { 25 | panic(err) 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /21-codegen/01-bindata/static/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/21-codegen/01-bindata/static/gopher.png -------------------------------------------------------------------------------- /21-codegen/02-embed/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | "net/http" 6 | ) 7 | 8 | type Handler struct { 9 | } 10 | 11 | //go:embed static/gopher.png 12 | var gopherPngBytes []byte 13 | 14 | func (*Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 15 | w.Header().Set("Content-Type", "image/png") 16 | w.Write(gopherPngBytes) 17 | } 18 | 19 | func main() { 20 | if err := http.ListenAndServe(":8081", new(Handler)); err != nil { 21 | panic(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /21-codegen/02-embed/static/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/21-codegen/02-embed/static/gopher.png -------------------------------------------------------------------------------- /21-codegen/02a-embed-fs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | //go:embed static 10 | var embedFiles embed.FS 11 | 12 | func main() { 13 | // fsys, err := fs.Sub(embedFiles, "static") 14 | // if err != nil { 15 | // log.Fatal(err) 16 | // } 17 | http.Handle("/", http.FileServer(http.FS(embedFiles))) 18 | if err := http.ListenAndServe(":8081", nil); err != nil { 19 | log.Fatal(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /21-codegen/02a-embed-fs/static/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/21-codegen/02a-embed-fs/static/gopher.png -------------------------------------------------------------------------------- /21-codegen/02a-embed-fs/static/other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/21-codegen/02a-embed-fs/static/other.png -------------------------------------------------------------------------------- /21-codegen/03-stringer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //go:generate stringer -type=MessageStatus 6 | type MessageStatus int 7 | 8 | const ( 9 | Sent MessageStatus = iota 10 | Received 11 | Rejected 12 | ) 13 | 14 | func main() { 15 | status := Sent 16 | fmt.Printf("Message is %s\n", status) // Message is Sent 17 | } 18 | 19 | // run with: go run main.go messagestatus_string.go 20 | -------------------------------------------------------------------------------- /21-codegen/03-stringer/messagestatus_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=MessageStatus"; DO NOT EDIT. 2 | 3 | package main 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[Sent-0] 12 | _ = x[Received-1] 13 | _ = x[Rejected-2] 14 | } 15 | 16 | const _MessageStatus_name = "SentReceivedRejected" 17 | 18 | var _MessageStatus_index = [...]uint8{0, 4, 12, 20} 19 | 20 | func (i MessageStatus) String() string { 21 | if i < 0 || i >= MessageStatus(len(_MessageStatus_index)-1) { 22 | return "MessageStatus(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _MessageStatus_name[_MessageStatus_index[i]:_MessageStatus_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /21-codegen/04-jsonenums/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | //go:generate jsonenums -type=Pill 9 | type Pill int 10 | 11 | const ( 12 | Placebo Pill = iota 13 | Aspirin 14 | Ibuprofen 15 | Paracetamol 16 | ) 17 | 18 | func main() { 19 | p, err := json.Marshal(Aspirin) 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | fmt.Println(string(p)) 25 | } 26 | -------------------------------------------------------------------------------- /21-codegen/05-easyjson/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/OtusGolang/webinars_practical_part/21-codegen/05-easyjson/student" 7 | ) 8 | 9 | // to install easyjson tool: 10 | // go get github.com/mailru/easyjson && go install github.com/mailru/easyjson/...@latest 11 | 12 | func main() { 13 | s := student.Student{ 14 | FirstName: "Otus", 15 | SecondName: "Otusov", 16 | Age: 25, 17 | Marks: map[student.Discipline]int{ 18 | "Golang": 5, 19 | "JavaScript": 3, 20 | }, 21 | } 22 | 23 | //data, err := json.Marshal(s) 24 | data, err := s.MarshalJSON() 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | fmt.Println(string(data)) 30 | } 31 | -------------------------------------------------------------------------------- /21-codegen/05-easyjson/student/student.go: -------------------------------------------------------------------------------- 1 | package student 2 | 3 | type Discipline = string 4 | 5 | //go:generate easyjson -all student.go 6 | type Student struct { 7 | FirstName string `json:"first_name"` 8 | SecondName string 9 | Age int 10 | Marks map[Discipline]int 11 | } 12 | -------------------------------------------------------------------------------- /21-codegen/06-impl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | // r *myReader io.Reader 6 | type myReader struct{} 7 | 8 | var _ io.Reader = (*myReader)(nil) 9 | -------------------------------------------------------------------------------- /21-codegen/07-mockgen/getter.go: -------------------------------------------------------------------------------- 1 | package mockgen 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | //go:generate mockgen -source=$GOFILE -destination ./mocks/mock_getter.go -package mocks Getter 10 | type Getter interface { 11 | Get(url string) (resp *http.Response, err error) 12 | } 13 | 14 | func GetPage(url string, opts ...Option) ([]byte, error) { 15 | options := GetPageOptions{ 16 | Getter: http.DefaultClient, 17 | } 18 | for _, o := range opts { 19 | o(&options) 20 | } 21 | 22 | resp, err := options.Getter.Get(url) 23 | if err != nil { 24 | return nil, fmt.Errorf("failed to GET %q: %w", url, err) 25 | } 26 | result, err := ioutil.ReadAll(resp.Body) 27 | return result, nil 28 | } 29 | -------------------------------------------------------------------------------- /21-codegen/07-mockgen/option.go: -------------------------------------------------------------------------------- 1 | package mockgen 2 | 3 | type GetPageOptions struct { 4 | Getter Getter 5 | } 6 | 7 | type Option func(*GetPageOptions) 8 | 9 | func WithGetter(g Getter) Option { 10 | return func(options *GetPageOptions) { 11 | options.Getter = g 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /21-codegen/09-ldflags/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var VersionString = "unset" 8 | 9 | func main() { 10 | fmt.Println("Version:", VersionString) 11 | } 12 | 13 | // go run -ldflags '-X main.VersionString=1.0' . 14 | -------------------------------------------------------------------------------- /21-codegen/10-protobuf/Person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package main; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | 7 | option go_package = ".;main"; 8 | 9 | enum Place { 10 | UNSET = 0; 11 | MOSCOW = 1; 12 | ST_PETERSBURG = 2; 13 | } 14 | 15 | message People { 16 | repeated Person person = 1; 17 | } 18 | 19 | message Person { 20 | string name = 1; 21 | repeated string mobile = 3; 22 | repeated string email = 4; 23 | Place place = 5; 24 | google.protobuf.Timestamp t = 6; 25 | } 26 | 27 | message Address { 28 | string street = 1; 29 | int32 number = 2; 30 | } 31 | -------------------------------------------------------------------------------- /21-codegen/10-protobuf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/golang/protobuf/proto" 8 | ) 9 | 10 | //go:generate protoc --go_out=. Person.proto 11 | 12 | func main() { 13 | p := new(Person) 14 | p.Name = "Anton" 15 | p.Mobile = append(p.Mobile, "8800553535") 16 | 17 | data, err := proto.Marshal(p) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | 22 | p1 := Person{} 23 | err = proto.Unmarshal(data, &p1) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | fmt.Printf("%+v", p1) 29 | } 30 | -------------------------------------------------------------------------------- /21-codegen/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/21-codegen 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cheekybits/genny v1.0.0 7 | github.com/ettle/strcase v0.2.0 8 | github.com/golang/mock v1.4.3 9 | github.com/golang/protobuf v1.4.1 10 | github.com/mailru/easyjson v0.9.0 11 | github.com/stretchr/testify v1.5.1 12 | google.golang.org/protobuf v1.25.0 13 | ) 14 | -------------------------------------------------------------------------------- /22-config-n-log/config/config.env: -------------------------------------------------------------------------------- 1 | HOST=localhost 2 | PORT=98888 3 | -------------------------------------------------------------------------------- /22-config-n-log/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceName": "go-is-very-otus_test", 3 | "directory": "${DIRECTORY}", 4 | "port": 700, 5 | "hosts": {"address": "test_host"} 6 | } 7 | -------------------------------------------------------------------------------- /22-config-n-log/config/config.toml: -------------------------------------------------------------------------------- 1 | [service] 2 | host = "localhost" 3 | port = 8888 4 | -------------------------------------------------------------------------------- /22-config-n-log/config/config.yml: -------------------------------------------------------------------------------- 1 | service_name: go-is-very-awesome 2 | -------------------------------------------------------------------------------- /22-config-n-log/jaeger/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | jaeger: 4 | image: jaegertracing/all-in-one:latest 5 | ports: 6 | - "6831:6831/udp" 7 | - "16686:16686" 8 | networks: 9 | - jaeger-example 10 | hotrod: 11 | image: jaegertracing/example-hotrod:latest 12 | ports: 13 | - "8080:8080" 14 | command: ["all"] 15 | environment: 16 | - JAEGER_AGENT_HOST=jaeger 17 | - JAEGER_AGENT_PORT=6831 18 | networks: 19 | - jaeger-example 20 | depends_on: 21 | - jaeger 22 | 23 | networks: 24 | jaeger-example: 25 | -------------------------------------------------------------------------------- /22-config-n-log/src/0_base/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "gopkg.in/yaml.v2" 7 | "io/ioutil" 8 | "log" 9 | ) 10 | 11 | var mainConfig config 12 | 13 | type config struct { 14 | ServiceName string `yaml:"service_name"` 15 | } 16 | 17 | func (m *config) parse() { 18 | var configPath = flag.String("config", "./config/config.yml", "path to config file") 19 | flag.Parse() 20 | 21 | configYml, err := ioutil.ReadFile(*configPath) 22 | if err != nil { 23 | log.Fatalf("reading config.yml error: %v", err) 24 | } 25 | 26 | err = yaml.Unmarshal(configYml, m) 27 | if err != nil { 28 | log.Fatalf("can't parse config.yml: %v", err) 29 | } 30 | } 31 | 32 | func main() { 33 | mainConfig.parse() 34 | fmt.Println(mainConfig.ServiceName) 35 | } 36 | -------------------------------------------------------------------------------- /22-config-n-log/src/10_zap_shugar/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | ) 6 | 7 | func main() { 8 | logger, _ := zap.NewProduction() 9 | defer logger.Sync() 10 | 11 | url := "test.test/best" 12 | slogger := logger.Sugar() 13 | slogger.Infof("failed to fetch %s", url) 14 | 15 | plain := slogger.Desugar() 16 | plain.DPanic("ending message", zap.String("msg", "this is the end")) 17 | } 18 | -------------------------------------------------------------------------------- /22-config-n-log/src/11_zap_prod/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "go.uber.org/zap" 7 | "go.uber.org/zap/zapcore" 8 | ) 9 | 10 | func main() { 11 | cfg := zap.NewProductionConfig() 12 | cfg.EncoderConfig.EncodeTime = syslogTimeEncoder 13 | cfg.EncoderConfig.EncodeLevel = customLevelEncoder 14 | 15 | logger, _ := cfg.Build() 16 | 17 | logger.Info("This should have a syslog style timestamp") 18 | } 19 | 20 | func syslogTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 21 | enc.AppendString(t.Format("Jan 2 15:04:05")) 22 | } 23 | 24 | func customLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) { 25 | enc.AppendString("[" + level.String() + "]") 26 | } 27 | -------------------------------------------------------------------------------- /22-config-n-log/src/13_slog/slog_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "golang.org/x/exp/slog" 8 | ) 9 | 10 | func TestSlog(t *testing.T) { 11 | slog.Info("Started", "count", 3) 12 | //logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: true})) 13 | logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) 14 | 15 | logger.Warn("aaaa!", "boom?", true) 16 | 17 | nestedLogger := logger.With("request_id", 42) 18 | 19 | processMessage(nestedLogger, "message to process") 20 | } 21 | 22 | func processMessage(nestedLogger *slog.Logger, s string) { 23 | nestedLogger.Info("start processing", "message", s) 24 | } 25 | -------------------------------------------------------------------------------- /22-config-n-log/src/1_env/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "strconv" 8 | ) 9 | 10 | type Config struct { 11 | Port int 12 | Host string 13 | } 14 | 15 | /* 16 | SHORTENER_HOST=localhost SHORTENER_PORT=7777 go run main.go 17 | */ 18 | 19 | func main() { 20 | httpPort, err := strconv.Atoi(os.Getenv("SHORTENER_PORT")) 21 | if err != nil { 22 | log.Fatal("SHORTENER_PORT is not defined") 23 | } 24 | 25 | shortenerHost := os.Getenv("SHORTENER_HOST") 26 | if shortenerHost == "" { 27 | log.Fatal("SHORTENER_HOST is not defined") 28 | } 29 | 30 | config := Config{httpPort, shortenerHost} 31 | fmt.Printf("%+v\n", config) 32 | } 33 | -------------------------------------------------------------------------------- /22-config-n-log/src/2_caarlos-env/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | 8 | "github.com/caarlos0/env/v6" 9 | ) 10 | 11 | type config struct { 12 | Home string `env:"HOME"` 13 | Port int `env:"PORT" envDefault:"3000"` 14 | IsProduction bool `env:"PRODUCTION,required"` 15 | Hosts []string `env:"HOSTS" envSeparator:":"` 16 | Duration time.Duration `env:"DURATION"` 17 | TempFolder string `env:"TEMP_FOLDER" envDefault:"${HOME}/tmp" envExpand:"true"` 18 | } 19 | 20 | /* 21 | PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run ./src/2_caarlos-env 22 | {Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s} 23 | */ 24 | func main() { 25 | cfg := config{} 26 | 27 | //opts := env.Options{Environment: map[string]string{ 28 | // "PRODUCTION": "true", 29 | //}} 30 | 31 | if err := env.Parse(&cfg); err != nil { 32 | log.Println(err) 33 | return 34 | } 35 | 36 | fmt.Printf("%+v\n", cfg) 37 | } 38 | -------------------------------------------------------------------------------- /22-config-n-log/src/4a_viper/config.yaml: -------------------------------------------------------------------------------- 1 | # url: "fromyaml.com" -------------------------------------------------------------------------------- /22-config-n-log/src/5_log1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | func main() { 8 | log.SetPrefix("LOG: ") 9 | log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile) 10 | 11 | // Println writes to the standard logger. 12 | log.Println("main started") 13 | // Fatalln is Println() followed by a call to os.Exit(1) 14 | log.Fatalln("fatal message") 15 | // Panicln is Println() followed by a call to panic() 16 | log.Panicln("panic message") 17 | } 18 | -------------------------------------------------------------------------------- /22-config-n-log/src/6_log2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | f, err := os.OpenFile("info.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 10 | if err != nil { 11 | log.Fatalf("error opening file: %v", err) 12 | } 13 | defer f.Close() 14 | log.SetOutput(f) 15 | log.Println("This is a test log entry") 16 | } 17 | -------------------------------------------------------------------------------- /22-config-n-log/src/8_zap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "go.uber.org/zap" 7 | ) 8 | 9 | func main() { 10 | logger := zap.NewExample() 11 | defer logger.Sync() // flushes buffer, if any 12 | 13 | url := "test.test/best" 14 | sugar := logger.Sugar() 15 | sugar.Infow("failed to fetch URL", 16 | // Structured context as loosely typed key-value pairs. 17 | "url", url, 18 | "attempt", 3, 19 | "backoff", time.Second, 20 | ) 21 | sugar.Infof("Failed to fetch URL: %s", url) 22 | } 23 | -------------------------------------------------------------------------------- /22-config-n-log/src/9_zap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "go.uber.org/zap" 7 | ) 8 | 9 | func main() { 10 | logger := zap.NewExample() 11 | defer logger.Sync() 12 | 13 | url := "test.test/best" 14 | logger.Info("failed to fetch URL", 15 | // Structured context as strongly typed Field values. 16 | zap.String("url", url), 17 | zap.Int("attempt", 3), 18 | zap.String("id", "3"), 19 | zap.Duration("backoff", time.Second), 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /23-no-sql/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an Alpine-based image 2 | FROM alpine:latest 3 | 4 | # Install Lua 5 | RUN apk add --no-cache lua5.3 6 | 7 | # Command to run Lua interpreter 8 | CMD ["lua5.3"] -------------------------------------------------------------------------------- /23-no-sql/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | mongodb: 5 | image: mongo:latest 6 | ports: 7 | - "27017:27017" 8 | volumes: 9 | - mongodb_data:/data/db 10 | 11 | redis: 12 | image: redis:latest 13 | ports: 14 | - "6379:6379" 15 | volumes: 16 | - redis_data:/data 17 | 18 | clickhouse: 19 | image: yandex/clickhouse-server:latest 20 | ports: 21 | - "8123:8123" 22 | - "9000:9000" 23 | volumes: 24 | - clickhouse_data:/var/lib/clickhouse 25 | 26 | aerospike: 27 | image: aerospike/aerospike-server:latest 28 | ports: 29 | - "3000:3000" 30 | volumes: 31 | - aerospike_data:/opt/aerospike/data 32 | 33 | lua: 34 | image: alpine:latest 35 | command: /bin/sh -c "apk add --no-cache lua5.3 && lua5.3" 36 | stdin_open: true 37 | tty: true 38 | 39 | volumes: 40 | mongodb_data: 41 | redis_data: 42 | clickhouse_data: 43 | aerospike_data: 44 | -------------------------------------------------------------------------------- /23-no-sql/redis/broker/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/go-redis/redis/v8" 6 | ) 7 | 8 | func main() { 9 | ctx := context.Background() 10 | client := redis.NewClient(&redis.Options{ 11 | Addr: "localhost:6379", // Адрес сервера Redis 12 | DB: 0, // Номер базы данных (по умолчанию 0) 13 | }) 14 | 15 | message := "Сообщение для обработки" 16 | queueName := "myqueue" 17 | 18 | // Отправка сообщения в очередь 19 | err := client.LPush(ctx, queueName, message).Err() 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | // Закрытие клиента Redis 25 | defer client.Close() 26 | } 27 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex1_slice_test.go: -------------------------------------------------------------------------------- 1 | package bench_test 2 | 3 | import "testing" 4 | 5 | func FillSlice() []int { 6 | const sz = 32000 7 | a := make([]int, 0) 8 | // a := make([]int, 0, sz) 9 | for i := 0; i < sz; i++ { 10 | a = append(a, i) 11 | } 12 | return a 13 | } 14 | 15 | func BenchmarkFillSlice(b *testing.B) { 16 | for i := 0; i < b.N; i++ { 17 | FillSlice() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex2_to_str_test.go: -------------------------------------------------------------------------------- 1 | package bench_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func toString(v int) string { 9 | return fmt.Sprintf("%d", v) 10 | // return strconv.Itoa(v) 11 | } 12 | 13 | func BenchmarkToString(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | toString(42) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex3_conc_test.go: -------------------------------------------------------------------------------- 1 | package bench 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var mu sync.Mutex 9 | var v int64 10 | 11 | func Sum() { 12 | mu.Lock() 13 | v++ 14 | mu.Unlock() 15 | } 16 | 17 | func BenchmarkConcurency(b *testing.B) { 18 | b.RunParallel(func(pb *testing.PB) { 19 | for pb.Next() { 20 | Sum() 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex4_concat_string_test.go: -------------------------------------------------------------------------------- 1 | package bench_test 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func ConcatString(m map[string]struct{}) string { 8 | a := "" 9 | for s := range m { 10 | a += s 11 | } 12 | return a 13 | } 14 | 15 | // func ConcatString(m map[string]struct{}) string { 16 | // builder := strings.Builder{} 17 | // for s := range m { 18 | // builder.WriteString(s) 19 | // } 20 | // return builder.String() 21 | // } 22 | 23 | func BenchmarkConcatString(b *testing.B) { 24 | m := map[string]struct{}{ 25 | "1": {}, 26 | "2": {}, 27 | "3": {}, 28 | "4": {}, 29 | "5": {}, 30 | } 31 | 32 | for i := 0; i < b.N; i++ { 33 | ConcatString(m) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex5_match_test.go: -------------------------------------------------------------------------------- 1 | package bench_test 2 | 3 | import ( 4 | "regexp" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | re *regexp.Regexp 10 | ) 11 | 12 | func match(str, match string) bool { 13 | res, _ := regexp.MatchString(match, str) 14 | return res 15 | 16 | // return re.MatchString(str) 17 | 18 | // return strings.Contains(str, match) 19 | } 20 | 21 | func BenchmarkMatch(b *testing.B) { 22 | re = regexp.MustCompile("world") 23 | 24 | for i := 0; i < b.N; i++ { 25 | match("Hello world of golang", "world") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/ex6_obj_reuse_test.go: -------------------------------------------------------------------------------- 1 | package bench_test 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | ) 7 | 8 | type A struct { 9 | I int 10 | } 11 | 12 | func BenchmarkReuseObject(b *testing.B) { 13 | buf := []byte("{\"I\": 32}") 14 | for i := 0; i < b.N; i++ { 15 | a := &A{} 16 | json.Unmarshal(buf, a) 17 | } 18 | } 19 | 20 | // func BenchmarkReuseObject(b *testing.B) { 21 | // buf := []byte("{\"I\": 32}") 22 | // a := &A{} 23 | // for i := 0; i < b.N; i++ { 24 | // *a = A{} 25 | // json.Unmarshal(buf, a) 26 | // } 27 | // } 28 | 29 | // func BenchmarkReuseObject(b *testing.B) { 30 | // p := sync.Pool{ 31 | // New: func() interface{} { 32 | // return &A{} 33 | // }, 34 | // } 35 | // buf := []byte("{\"I\": 32}") 36 | // for i := 0; i < b.N; i++ { 37 | // a := p.Get().(*A) 38 | // json.Unmarshal(buf, a) 39 | // *a = A{} 40 | // p.Put(a) 41 | // } 42 | // } 43 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/go.mod: -------------------------------------------------------------------------------- 1 | module otus.ru/benchtest 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/optimization/go.mod: -------------------------------------------------------------------------------- 1 | module optimization 2 | 3 | go 1.14 4 | 5 | require github.com/stretchr/testify v1.6.1 6 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/optimization/top10.go: -------------------------------------------------------------------------------- 1 | package optimization 2 | 3 | import ( 4 | "sort" 5 | "strings" 6 | ) 7 | 8 | type WordCounter struct { 9 | word string 10 | count int 11 | } 12 | 13 | func Top10(text string) []string { 14 | splittedText := strings.Fields(text) 15 | 16 | m := make(map[string]int) 17 | for _, word := range splittedText { 18 | m[word]++ 19 | } 20 | 21 | wordCounter := make([]WordCounter, 0, len(m)) 22 | for k, v := range m { 23 | wordCounter = append(wordCounter, WordCounter{ 24 | word: k, 25 | count: v, 26 | }) 27 | } 28 | 29 | sort.Slice(wordCounter, func(i, j int) bool { 30 | return wordCounter[i].count > wordCounter[j].count 31 | }) 32 | 33 | resLen := 10 34 | if resLen > len(wordCounter) { 35 | resLen = len(wordCounter) 36 | } 37 | res := make([]string, resLen) 38 | 39 | for i := range res { 40 | res[i] = wordCounter[i].word 41 | } 42 | 43 | return res 44 | } 45 | -------------------------------------------------------------------------------- /23-profiling/00_lesson/pprofsrv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | _ "net/http/pprof" 7 | ) 8 | 9 | type Resp struct { 10 | Msgs []string 11 | } 12 | 13 | func handler(w http.ResponseWriter, r *http.Request) { 14 | resp := Resp{ 15 | Msgs: make([]string, 10), 16 | } 17 | for i := 0; i < len(resp.Msgs); i++ { 18 | resp.Msgs[i] = "hello world" 19 | } 20 | res, _ := json.Marshal(resp) 21 | w.Write(res) 22 | } 23 | 24 | func main() { 25 | http.HandleFunc("/", handler) 26 | 27 | http.ListenAndServe(":7070", nil) 28 | } 29 | -------------------------------------------------------------------------------- /23-profiling/01_bench/ex.txt: -------------------------------------------------------------------------------- 1 | go test -bench=. . 2 | go test -bench=. -benchmem . 3 | go test -bench=. -benchmem -cpuprofile=cpu.out -memprofile=mem.out . 4 | -------------------------------------------------------------------------------- /23-profiling/01_bench/exbench.go: -------------------------------------------------------------------------------- 1 | package exbench 2 | 3 | func Fast() int { 4 | acc := new(int) 5 | for i := 0; i < 10; i++ { 6 | acc2 := new(int) 7 | *acc2 = *acc + 1 8 | acc = acc2 9 | } 10 | 11 | return *acc 12 | } 13 | 14 | func Slow() int { 15 | acc := new(int) 16 | for i := 0; i < 1000; i++ { 17 | acc2 := new(int) 18 | *acc2 = *acc + 1 19 | acc = acc2 20 | } 21 | 22 | return *acc 23 | } -------------------------------------------------------------------------------- /23-profiling/01_bench/exbench_test.go: -------------------------------------------------------------------------------- 1 | package exbench 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } -------------------------------------------------------------------------------- /23-profiling/02_benchpar/benchpar.go: -------------------------------------------------------------------------------- 1 | package benchpar 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | var ( 8 | mu = sync.Mutex{} 9 | ) 10 | 11 | func Fast() int { 12 | acc := 0 13 | for i := 0; i < 1000; i++ { 14 | acc++ 15 | } 16 | 17 | return acc 18 | } 19 | 20 | func Slow() int { 21 | mu.Lock() 22 | defer mu.Unlock() 23 | 24 | acc := 0 25 | for i := 0; i < 1000; i++ { 26 | acc++ 27 | } 28 | 29 | return acc 30 | } 31 | -------------------------------------------------------------------------------- /23-profiling/02_benchpar/ex.txt: -------------------------------------------------------------------------------- 1 | go test -bench . -------------------------------------------------------------------------------- /23-profiling/02_benchpar/exbenchpar_test.go: -------------------------------------------------------------------------------- 1 | package benchpar 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func BenchmarkFast(b *testing.B) { 8 | for i := 0; i < b.N; i++ { 9 | Fast() 10 | } 11 | } 12 | 13 | func BenchmarkSlow(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | Slow() 16 | } 17 | } 18 | 19 | func BenchmarkParallelFast(b *testing.B) { 20 | b.RunParallel(func(pb *testing.PB) { 21 | for pb.Next() { 22 | Fast() 23 | } 24 | }) 25 | } 26 | 27 | func BenchmarkParallelSlow(b *testing.B) { 28 | b.RunParallel(func(pb *testing.PB) { 29 | for pb.Next() { 30 | Slow() 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /23-profiling/03_prealloc/prealloc.go: -------------------------------------------------------------------------------- 1 | package prealloc 2 | 3 | func Fast() { 4 | const sz = 32000 5 | a := make([]int, 0) 6 | for i := 0; i < sz; i++ { 7 | a = append(a, i) 8 | } 9 | } 10 | 11 | func Slow() { 12 | const sz = 32000 13 | a := make([]int, 0, sz) 14 | for i := 0; i < sz; i++ { 15 | a = append(a, i) 16 | } 17 | } 18 | 19 | func Slow1() { 20 | const sz = 32000 21 | a := make([]int, sz, sz) 22 | for i := 0; i < sz; i++ { 23 | a[i] = i 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /23-profiling/03_prealloc/prealloc_test.go: -------------------------------------------------------------------------------- 1 | package prealloc 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } 16 | 17 | func BenchmarkSlow1(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | Slow1() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /23-profiling/04_reuse/reuse.go: -------------------------------------------------------------------------------- 1 | package reuse 2 | 3 | import "encoding/json" 4 | 5 | type A struct { 6 | I int 7 | } 8 | 9 | func Slow() { 10 | for i := 0; i < 1000; i++ { 11 | a := &A{} 12 | json.Unmarshal([]byte("{\"i\": 32}"), a) 13 | } 14 | } 15 | 16 | func Fast() { 17 | a := &A{} 18 | for i := 0; i < 1000; i++ { 19 | json.Unmarshal([]byte("{\"i\": 32}"), a) 20 | } 21 | } -------------------------------------------------------------------------------- /23-profiling/04_reuse/reuse_test.go: -------------------------------------------------------------------------------- 1 | package reuse 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } -------------------------------------------------------------------------------- /23-profiling/05_fmtvsstrconv/fmtvsstrconv.go: -------------------------------------------------------------------------------- 1 | package fmtvsstrconv 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | func Slow() string { 9 | return fmt.Sprintf("%d",42) 10 | } 11 | 12 | func Fast() string { 13 | return strconv.Itoa(42) 14 | } 15 | -------------------------------------------------------------------------------- /23-profiling/05_fmtvsstrconv/fmtvsstrconv_test.go: -------------------------------------------------------------------------------- 1 | package fmtvsstrconv 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } -------------------------------------------------------------------------------- /23-profiling/06_stringsvsre/stringsvsre.go: -------------------------------------------------------------------------------- 1 | package stringsvsre 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | var ( 9 | re *regexp.Regexp 10 | ) 11 | 12 | func Fast() bool { 13 | return strings.Contains("Hello world of golang", "world") 14 | } 15 | 16 | func VerySlow() bool { 17 | res, _ := regexp.MatchString("world", "Hello world of golang") 18 | return res 19 | } 20 | 21 | func Slow() bool { 22 | return re.MatchString("Hello world of golang") 23 | } 24 | 25 | func init() { 26 | re, _ = regexp.Compile("world") 27 | } -------------------------------------------------------------------------------- /23-profiling/06_stringsvsre/stringsvsre_test.go: -------------------------------------------------------------------------------- 1 | package stringsvsre 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } 16 | 17 | func BenchmarkVerySlow(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | VerySlow() 20 | } 21 | } -------------------------------------------------------------------------------- /23-profiling/07_stringbuilder/stringbuilder.go: -------------------------------------------------------------------------------- 1 | package stringbuilder 2 | 3 | import "strings" 4 | 5 | func Slow() string { 6 | a := "" 7 | a += "1" 8 | a += "2" 9 | a += "3" 10 | a += "4" 11 | a += "5" 12 | return a 13 | } 14 | 15 | func Fast() string { 16 | builder := strings.Builder{} 17 | builder.WriteString("1") 18 | builder.WriteString("2") 19 | builder.WriteString("3") 20 | builder.WriteString("4") 21 | builder.WriteString("5") 22 | return builder.String() 23 | } 24 | 25 | func VeryFast() string { 26 | return "1" + "2" + "3" + "4" + "5" 27 | } -------------------------------------------------------------------------------- /23-profiling/07_stringbuilder/stringbuilder_test.go: -------------------------------------------------------------------------------- 1 | package stringbuilder 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } 16 | 17 | func BenchmarkVeryFast(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | VeryFast() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /23-profiling/08_syncpool/syncpool.go: -------------------------------------------------------------------------------- 1 | package syncpool 2 | 3 | import ( 4 | "strings" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | pool = sync.Pool{ 10 | New: func() interface{} { 11 | return &strings.Builder{} 12 | }, 13 | } 14 | ) 15 | 16 | func Slow() string { 17 | builder := strings.Builder{} 18 | builder.WriteString("Hello") 19 | return builder.String() 20 | } 21 | 22 | func Fast() string { 23 | builder := pool.Get().(*strings.Builder) 24 | defer pool.Put(builder) //Try to comment it out! 25 | builder.Reset() 26 | builder.WriteString("Hello") 27 | res := builder.String() 28 | return res 29 | } -------------------------------------------------------------------------------- /23-profiling/08_syncpool/syncpool_test.go: -------------------------------------------------------------------------------- 1 | package syncpool 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func BenchmarkFast(b *testing.B) { 8 | for i := 0; i < b.N; i++ { 9 | Fast() 10 | } 11 | } 12 | 13 | func BenchmarkSlow(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | Slow() 16 | } 17 | } 18 | 19 | func BenchmarkParallelFast(b *testing.B) { 20 | b.RunParallel(func(pb *testing.PB) { 21 | for pb.Next() { 22 | Fast() 23 | } 24 | }) 25 | } 26 | 27 | func BenchmarkParallelSlow(b *testing.B) { 28 | b.RunParallel(func(pb *testing.PB) { 29 | for pb.Next() { 30 | Slow() 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /23-profiling/09_pointerkeys/pointerkeys.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | const ( 11 | numElements = 10000000 12 | ) 13 | 14 | var foo = map[string]int{} 15 | 16 | func timeGC() { 17 | t := time.Now() 18 | runtime.GC() 19 | fmt.Printf("gc took: %s\n", time.Since(t)) 20 | } 21 | 22 | func main() { 23 | for i := 0; i < numElements; i++ { 24 | foo[strconv.Itoa(i)] = i 25 | } 26 | 27 | for { 28 | timeGC() 29 | time.Sleep(1 * time.Second) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /23-profiling/10_exjs/exjs.go: -------------------------------------------------------------------------------- 1 | package exjs 2 | 3 | import "encoding/json" 4 | 5 | var ( 6 | JsonExample = []byte("{\"I\": 10}") 7 | ) 8 | 9 | //easyjson:json 10 | type A struct { 11 | I int 12 | } 13 | 14 | func StandardMarshal() { 15 | a := &A{15} 16 | json.Marshal(a) 17 | } 18 | 19 | func StandardUnmarshal() { 20 | a := &A{} 21 | json.Unmarshal(JsonExample, &a) 22 | } 23 | 24 | func EasyMarshal() { 25 | a := &A{15} 26 | a.MarshalJSON() 27 | } 28 | 29 | func EasyUnmarshal() { 30 | a := &A{} 31 | a.UnmarshalJSON(JsonExample) 32 | } -------------------------------------------------------------------------------- /23-profiling/10_exjs/exjs_test.go: -------------------------------------------------------------------------------- 1 | package exjs 2 | 3 | import "testing" 4 | 5 | func BenchmarkStandardMarshal(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | StandardMarshal() 8 | } 9 | } 10 | 11 | func BenchmarkStandardUnmarshal(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | StandardUnmarshal() 14 | } 15 | } 16 | 17 | func BenchmarkEasyMarshal(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | EasyMarshal() 20 | } 21 | } 22 | 23 | func BenchmarkEasyUnmarshal(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | EasyMarshal() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /23-profiling/11_generics/generics.go: -------------------------------------------------------------------------------- 1 | package generics 2 | 3 | import ( 4 | "golang.org/x/exp/constraints" 5 | ) 6 | 7 | func ConvertMapWithoutGenerics(a map[string]int32) map[string]int64 { 8 | newMap := make(map[string]int64) 9 | 10 | for key, value := range a { 11 | newMap[key] = int64(value) 12 | } 13 | 14 | return newMap 15 | } 16 | 17 | func ConvertMapWithGenerics[K comparable, FROM, TO constraints.Integer](in map[K]FROM) map[K]TO { 18 | nMap := make(map[K]TO, len(in)) 19 | for k, v := range in { 20 | nMap[k] = TO(v) 21 | } 22 | return nMap 23 | } 24 | 25 | func GMax[T interface{ string | int }](a, b T) T { 26 | if a > b { 27 | return a 28 | } 29 | return b 30 | } 31 | 32 | func IMax(a, b int) int { 33 | if a > b { 34 | return a 35 | } 36 | return b 37 | } 38 | 39 | func SMax(a, b string) string { 40 | if a > b { 41 | return a 42 | } 43 | return b 44 | } 45 | -------------------------------------------------------------------------------- /23-profiling/11_generics/generics_test.go: -------------------------------------------------------------------------------- 1 | package generics 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // Benchmark for the function with empty interfaces 8 | func BenchmarkFunctionWithoutGenerics(b *testing.B) { 9 | for i := 0; i < b.N; i++ { 10 | ConvertMapWithoutGenerics(map[string]int32{"1": 1, "2": 2}) 11 | } 12 | } 13 | 14 | // Benchmark for the function with generics 15 | func BenchmarkFunctionWithGenerics(b *testing.B) { 16 | convertMap := ConvertMapWithGenerics[string, int32, int64] 17 | for i := 0; i < b.N; i++ { 18 | convertMap(map[string]int32{"1": 1, "2": 2}) 19 | } 20 | } 21 | 22 | func BenchmarkGmaxString(b *testing.B) { 23 | for i := 0; i < b.N; i++ { 24 | GMax("a", "b") 25 | } 26 | } 27 | 28 | func BenchmarkSmax(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | SMax("a", "b") 31 | } 32 | } 33 | 34 | func BenchmarkGmaxInt(b *testing.B) { 35 | for i := 0; i < b.N; i++ { 36 | GMax(1, 2) 37 | } 38 | } 39 | 40 | func BenchmarkImax(b *testing.B) { 41 | for i := 0; i < b.N; i++ { 42 | IMax(1, 2) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /23-profiling/12_httpserver/standard.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | //_ "net/http/pprof" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 11 | fmt.Fprintf(w, "Hello, world!\n\n") 12 | }) 13 | 14 | http.ListenAndServe(":8080", nil) 15 | } 16 | -------------------------------------------------------------------------------- /23-profiling/12_httpserver/test.txt: -------------------------------------------------------------------------------- 1 | ./wrk -c100 -d20s -t50 http://127.0.0.1:8080/ -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/13_pprof_console.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/23-profiling/13_pprof_console/13_pprof_console.test -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/cpu.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/23-profiling/13_pprof_console/cpu.out -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/help.txt: -------------------------------------------------------------------------------- 1 | go test -bench=. -benchmem -cpuprofile=cpu.out -memprofile=mem.out -x . 2 | go tool pprof 13_pprof_console.test cpu.out 3 | list Slow 4 | list Fast 5 | go tool pprof 13_pprof_console.test mem.out 6 | alloc_objects 7 | alloc_space 8 | inuse_objects 9 | inuse_space 10 | list Slow 11 | list Fast -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/mem.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/23-profiling/13_pprof_console/mem.out -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/prealloc.go: -------------------------------------------------------------------------------- 1 | package prealloc 2 | 3 | func Fast() { 4 | const sz = 32000 5 | a := make([]int, 0) 6 | for i := 0; i < sz; i++ { 7 | a = append(a, i) 8 | } 9 | } 10 | 11 | func Slow() { 12 | const sz = 32000 13 | a := make([]int, 0, sz) 14 | for i := 0; i < sz; i++ { 15 | a = append(a, i) 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /23-profiling/13_pprof_console/prealloc_test.go: -------------------------------------------------------------------------------- 1 | package prealloc 2 | 3 | import "testing" 4 | 5 | func BenchmarkFast(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | Fast() 8 | } 9 | } 10 | 11 | func BenchmarkSlow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | Slow() 14 | } 15 | } -------------------------------------------------------------------------------- /23-profiling/14_pprof_svg_and_web/help.txt: -------------------------------------------------------------------------------- 1 | ./wrk -c100 -d2000s -t50 http://127.0.0.1:8080/ 2 | go tool pprof http://localhost:8080/debug/pprof/profile?seconds=5 3 | go tool pprof http://localhost:8080/debug/pprof/goroutines -------------------------------------------------------------------------------- /23-profiling/14_pprof_svg_and_web/standard.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | _ "net/http/pprof" 8 | ) 9 | 10 | type Resp struct { 11 | Status int 12 | } 13 | 14 | func handler(w http.ResponseWriter, r *http.Request) { 15 | for i := 0; i < 1000; i++ { 16 | resp := &Resp{200} 17 | res, _ := json.Marshal(resp) 18 | fmt.Fprintln(w, res) 19 | } 20 | fmt.Fprintln(w, "Hello, world!\n\n") 21 | } 22 | 23 | func main() { 24 | http.HandleFunc("/", handler) 25 | 26 | http.ListenAndServe(":8080", nil) 27 | } 28 | -------------------------------------------------------------------------------- /23-profiling/15_flamegraph/help.txt: -------------------------------------------------------------------------------- 1 | go get github.com/uber/go-torch 2 | git clone https://github.com/brendangregg/FlameGraph 3 | cd FlameGraph 4 | go-torch -------------------------------------------------------------------------------- /23-profiling/15_flamegraph/standard.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | _ "net/http/pprof" 8 | ) 9 | 10 | type Resp struct { 11 | Status int 12 | } 13 | 14 | func handler(w http.ResponseWriter, r *http.Request) { 15 | for i := 0; i < 1000; i++ { 16 | resp := &Resp{200} 17 | res, _ := json.Marshal(resp) 18 | fmt.Fprintln(w, res) 19 | } 20 | fmt.Fprintln(w, "Hello, world!\n\n") 21 | } 22 | 23 | func main() { 24 | http.HandleFunc("/", handler) 25 | 26 | http.ListenAndServe(":8080", nil) 27 | } 28 | -------------------------------------------------------------------------------- /23-profiling/16_trace/help.txt: -------------------------------------------------------------------------------- 1 | ./wrk -c100 -d2000s -t50 http://127.0.0.1:8080/ 2 | wget http://localhost:8080/debug/pprof/trace?seconds=5 -o trace.out 3 | go tool trace trace.out -------------------------------------------------------------------------------- /23-profiling/16_trace/standard.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | _ "net/http/pprof" 8 | ) 9 | 10 | type Resp struct { 11 | Status int 12 | } 13 | 14 | func handler(w http.ResponseWriter, r *http.Request) { 15 | for i := 0; i < 1000; i++ { 16 | resp := &Resp{200} 17 | res, _ := json.Marshal(resp) 18 | fmt.Fprintln(w, res) 19 | } 20 | fmt.Fprintln(w, "Hello, world!\n\n") 21 | } 22 | 23 | func main() { 24 | http.HandleFunc("/", handler) 25 | 26 | http.ListenAndServe(":8080", nil) 27 | } 28 | -------------------------------------------------------------------------------- /23-profiling/16_trace/trace.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/23-profiling/16_trace/trace.out -------------------------------------------------------------------------------- /24-context-n-net/03-udp-server/udpserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | ) 8 | 9 | //TODO: Make worker 10 | 11 | //TODO: SHOW BROADCAST 12 | 13 | func main() { 14 | addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:3303") 15 | 16 | l, err := net.ListenUDP("udp", addr) 17 | if err != nil { 18 | log.Fatalf("Cannot listen") 19 | } 20 | 21 | defer l.Close() 22 | 23 | msg := make([]byte, 1024) 24 | for { 25 | length, fromAddr, err := l.ReadFromUDP(msg) 26 | if err != nil { 27 | log.Fatalf("Error happened") 28 | } 29 | 30 | fmt.Printf("Message from %s with length %d: %s\n", fromAddr.String(), length, string(msg)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /24-context-n-net/04-udp-client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | serverAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:3303") 11 | if err != nil { 12 | log.Fatalf("cannot resolve server addr: %v", err) 13 | } 14 | 15 | conn, err := net.DialUDP("udp", nil, serverAddr) 16 | if err != nil { 17 | log.Fatalf("cannot dial to server: %v", err) 18 | } 19 | 20 | order := 0 21 | for { 22 | msg := "" 23 | switch order { 24 | case 0: 25 | msg = "qwertyuiop" 26 | order++ 27 | case 1: 28 | msg = "asdfghjkl" 29 | order++ 30 | case 2: 31 | msg = "zxcvbnm" 32 | order = 0 33 | } 34 | 35 | _, err := conn.Write([]byte(msg)) 36 | if err != nil { 37 | log.Fatalf("cannot send: %v", err) 38 | } 39 | time.Sleep(1 * time.Second) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /24-context-n-net/05-dns-resolver/resolve.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net" 7 | ) 8 | 9 | func main() { 10 | resolver := net.Resolver{ 11 | PreferGo: true, 12 | StrictErrors: false, 13 | Dial: nil, 14 | } 15 | 16 | ctx := context.Background() 17 | 18 | addrs, err := resolver.LookupIPAddr(ctx, "mail.ru") 19 | if err != nil { 20 | log.Fatalf("cannot lookup addr: %v", err) 21 | } 22 | 23 | for _, addr := range addrs { 24 | log.Printf("addr of mail.ru: %s", addr) 25 | } 26 | 27 | mxes, err := resolver.LookupMX(ctx, "bk.ru") 28 | if err != nil { 29 | log.Fatalf("cannot lookup mx: %v", err) 30 | } 31 | 32 | for _, mx := range mxes { 33 | log.Printf("mx of mail.ru: %s (pref=%d)", mx.Host, mx.Pref) 34 | } 35 | 36 | txts, err := resolver.LookupTXT(ctx, "mail.ru") 37 | if err != nil { 38 | log.Fatalf("cannot lookup txt: %v", err) 39 | } 40 | 41 | for _, txt := range txts { 42 | log.Printf("txt of mail.ru: %s", txt) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /24-context-n-net/06-context/context.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "math/rand" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | func emulateLongOperation(ctx context.Context, id int) { 12 | randVal := rand.Intn(5000) 13 | randTime := time.Duration(randVal) * time.Millisecond 14 | log.Printf("Job %d Will be evalutated for %d", id, randVal) 15 | timer := time.NewTimer(randTime) 16 | 17 | select { 18 | case <-timer.C: 19 | log.Printf("Successfully finished job %d", id) 20 | case <-ctx.Done(): 21 | log.Printf("id %d timed out", id) 22 | } 23 | } 24 | 25 | func main() { 26 | wg := sync.WaitGroup{} 27 | ctx, cancel := context.WithTimeout(context.Background(), 2000*time.Millisecond) 28 | for i := 0; i < 10; i++ { 29 | wg.Add(1) 30 | go func(id int) { 31 | emulateLongOperation(ctx, id) 32 | wg.Done() 33 | }(i) 34 | } 35 | 36 | time.Sleep(time.Second) 37 | cancel() 38 | wg.Wait() 39 | } 40 | -------------------------------------------------------------------------------- /24-context-n-net/06b-context/context.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/rand" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | wg := &sync.WaitGroup{} 13 | ctx := context.Background() 14 | ctx, _ = context.WithTimeout(ctx, time.Second) 15 | wg.Add(1) 16 | go dealLongWithCtx(wg, ctx) 17 | wg.Wait() 18 | } 19 | 20 | func dealLongWithCtx(wg *sync.WaitGroup, ctx context.Context) { 21 | defer wg.Done() 22 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 23 | randVal := r.Intn(2000) 24 | randTime := time.Duration(randVal) * time.Millisecond 25 | timer := time.NewTimer(randTime) 26 | fmt.Printf("wait for %s \n", randTime) 27 | select { 28 | case <-timer.C: 29 | fmt.Println("Done") 30 | case <-ctx.Done(): 31 | fmt.Println("Canceled") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /24-context-n-net/07-signal-notyfy-context/signal.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "os/signal" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | ctx1, stop := signal.NotifyContext(context.Background(), os.Interrupt) 14 | defer stop() 15 | 16 | ctx, cancel := context.WithTimeout(ctx1, time.Second*2) 17 | defer cancel() 18 | 19 | cmd := exec.CommandContext(ctx, "sleep", "10") 20 | err := cmd.Run() 21 | if err != nil { 22 | if ctx.Err() != nil { 23 | fmt.Printf("ctx error:%v\n", ctx.Err()) 24 | } else { 25 | fmt.Printf("run error:%v\n", err) 26 | } 27 | os.Exit(1) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /24-context-n-net/08-gracefull-stop/gracefullstop.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net/http" 9 | "os" 10 | "os/signal" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) 16 | //ctx, stop := context.WithCancel(context.Background()) 17 | defer stop() 18 | 19 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 20 | _, _ = io.WriteString(w, "hello world\n") 21 | }) 22 | 23 | server := &http.Server{ 24 | Addr: ":8888", 25 | Handler: nil, 26 | } 27 | 28 | go func() { 29 | <-ctx.Done() 30 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 31 | defer cancel() 32 | _ = server.Shutdown(ctx) 33 | }() 34 | fmt.Println("start receiving at: 8888") 35 | log.Fatal(server.ListenAndServe()) 36 | } 37 | -------------------------------------------------------------------------------- /24-context-n-net/10-context-with-cancel/context_with_cancel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx := context.Background() 11 | cancelCtx, cancelFunc := context.WithCancel(ctx) 12 | go task(cancelCtx) 13 | time.Sleep(time.Second * 3) 14 | cancelFunc() 15 | time.Sleep(time.Second * 1) 16 | } 17 | 18 | func task(ctx context.Context) { 19 | i := 1 20 | for { 21 | select { 22 | case <-ctx.Done(): 23 | fmt.Println("Gracefully exit") 24 | fmt.Println(ctx.Err()) 25 | return 26 | default: 27 | fmt.Println(i) 28 | time.Sleep(time.Second * 1) 29 | i++ 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /24-context-n-net/11-context-with-timeout/context_with_timeout.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx := context.Background() 11 | cancelCtx, cancel := context.WithTimeout(ctx, time.Second*3) 12 | defer cancel() 13 | go task1(cancelCtx) 14 | time.Sleep(time.Second * 4) 15 | } 16 | 17 | func task1(ctx context.Context) { 18 | i := 1 19 | for { 20 | select { 21 | case <-ctx.Done(): 22 | fmt.Println("Gracefully exit") 23 | fmt.Println(ctx.Err()) 24 | return 25 | default: 26 | fmt.Println(i) 27 | time.Sleep(time.Second * 1) 28 | i++ 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /24-context-n-net/12-context-with-deadline/context-with-deadline.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | ctx := context.Background() 11 | cancelCtx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second*5)) 12 | defer cancel() 13 | go task(cancelCtx) 14 | time.Sleep(time.Second * 6) 15 | } 16 | 17 | func task(ctx context.Context) { 18 | i := 1 19 | for { 20 | select { 21 | case <-ctx.Done(): 22 | fmt.Println("Gracefully exit") 23 | fmt.Println(ctx.Err()) 24 | return 25 | default: 26 | fmt.Println(i) 27 | time.Sleep(time.Second * 1) 28 | i++ 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /25-sql/configs/local.toml: -------------------------------------------------------------------------------- 1 | [psql] 2 | dsn = "host=localhost port=5432 user=anthony password=anthony dbname=books sslmode=disable" 3 | -------------------------------------------------------------------------------- /25-sql/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/25-sql 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/BurntSushi/toml v0.3.1 7 | github.com/jackc/pgx/v4 v4.9.2 8 | golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 // indirect 9 | golang.org/x/text v0.3.4 // indirect 10 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /25-sql/internal/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/OtusGolang/webinars_practical_part/25-sql/internal/repository" 8 | ) 9 | 10 | type App struct { 11 | r repository.BaseRepo 12 | } 13 | 14 | func New(r repository.BaseRepo) (*App, error) { 15 | return &App{r: r}, nil 16 | } 17 | 18 | func (a *App) Run(ctx context.Context) error { 19 | books, err := a.r.GetBooks(ctx) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | log.Println("books:") 25 | for _, b := range books { 26 | log.Printf("\t %+v", b) 27 | } 28 | 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /25-sql/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/BurntSushi/toml" 4 | 5 | func Read(fpath string) (c Config, err error) { 6 | _, err = toml.DecodeFile(fpath, &c) 7 | return 8 | } 9 | 10 | type Config struct { 11 | PSQL PSQLConfig 12 | } 13 | 14 | type PSQLConfig struct { 15 | DSN string 16 | } 17 | -------------------------------------------------------------------------------- /25-sql/internal/repository/repository.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | type BooksRepo interface { 11 | GetBooks(ctx context.Context) ([]Book, error) 12 | } 13 | 14 | type BaseRepo interface { 15 | Connect(ctx context.Context, dsn string) error 16 | Close() error 17 | BooksRepo 18 | } 19 | 20 | type Book struct { 21 | Title string 22 | CreatedAt time.Time 23 | UpdatedAt time.Time 24 | Meta BookMeta 25 | } 26 | 27 | type BookMeta struct { 28 | Author string 29 | } 30 | 31 | func (b *BookMeta) Scan(src interface{}) error { 32 | if src == nil { 33 | return nil 34 | } 35 | 36 | d, ok := src.([]byte) 37 | if !ok { 38 | return fmt.Errorf("unsupported type: %T", src) 39 | } 40 | return json.Unmarshal(d, b) 41 | } 42 | -------------------------------------------------------------------------------- /25-sql/migrations/20200528084542_init.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE table books ( 3 | id serial primary key, 4 | title text, 5 | description text, 6 | meta jsonb, 7 | created_at timestamptz not null default now(), 8 | updated_at timestamptz 9 | ); 10 | 11 | INSERT INTO books (title, description, meta, updated_at) 12 | VALUES 13 | ('Мастер и Маргарита', 'test description 1', '{}', now()), 14 | ('Граф Монте-Кристо', 'test description 2', null, null), 15 | ('Марсианин', 'test description 3', '{"author": "Энди Вейер"}', now()); 16 | 17 | -- +goose Down 18 | drop table books; 19 | -------------------------------------------------------------------------------- /26-grpc-2/chat/api/chat.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc --go_out=./ --go_opt=paths=source_relative --go-grpc_out=./ --go-grpc_opt=paths=source_relative proto/chat.proto 2 | package api 3 | -------------------------------------------------------------------------------- /26-grpc-2/chat/api/proto/chat.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package chat; 4 | 5 | import "google/protobuf/empty.proto"; 6 | 7 | option go_package = "chat/api/proto;proto"; 8 | 9 | service ChatService { 10 | rpc Chat(stream Message) returns (stream Message); 11 | rpc StartCount(google.protobuf.Empty) returns (stream Message); 12 | } 13 | 14 | message Message { 15 | string content = 1; 16 | } 17 | -------------------------------------------------------------------------------- /26-grpc-2/chat/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | chatproto "chat/api/proto" 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | func main() { 13 | conn, err := grpc.Dial(":50052", grpc.WithInsecure()) 14 | if err != nil { 15 | log.Fatalf("did not connect: %v", err) 16 | } 17 | defer conn.Close() 18 | 19 | c := chatproto.NewChatServiceClient(conn) 20 | 21 | stream, err := c.Chat(context.Background()) 22 | if err != nil { 23 | log.Fatalf("error creating stream: %v", err) 24 | } 25 | for i := 0; i < 100; i++ { 26 | // Send a message to the server. 27 | msg := &chatproto.Message{Content: "Hello, server!"} 28 | if err := stream.Send(msg); err != nil { 29 | log.Fatalf("failed to send: %v", err) 30 | } 31 | 32 | // Receive a message from the server. 33 | response, err := stream.Recv() 34 | if err != nil { 35 | log.Fatalf("error receiving: %v", err) 36 | } 37 | log.Printf("Received: %s", response.Content) 38 | time.Sleep(1 * time.Second) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /26-grpc-2/chat/go.mod: -------------------------------------------------------------------------------- 1 | module chat 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/gogo/protobuf v1.3.2 7 | google.golang.org/grpc v1.59.0 8 | google.golang.org/protobuf v1.31.0 9 | ) 10 | 11 | require ( 12 | github.com/golang/protobuf v1.5.3 // indirect 13 | github.com/google/go-cmp v0.6.0 // indirect 14 | golang.org/x/net v0.17.0 // indirect 15 | golang.org/x/sys v0.13.0 // indirect 16 | golang.org/x/text v0.13.0 // indirect 17 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /26-grpc-2/int-sint/go.mod: -------------------------------------------------------------------------------- 1 | module benchs 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/golang/protobuf v1.5.0 7 | google.golang.org/protobuf v1.31.0 8 | ) 9 | -------------------------------------------------------------------------------- /26-grpc-2/int-sint/go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= 2 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 3 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 4 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 5 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 6 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 7 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 8 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 9 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 10 | -------------------------------------------------------------------------------- /26-grpc-2/int-sint/main.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc --go_out=./ --go_opt=paths=source_relative --go-grpc_out=./ --go-grpc_opt=paths=source_relative proto/benchmark.proto 2 | 3 | package main 4 | 5 | func main() { 6 | } 7 | -------------------------------------------------------------------------------- /26-grpc-2/int-sint/proto/benchmark.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package benchmark; 4 | option go_package = "benchs/benchmark/proto;proto"; 5 | 6 | 7 | message Sint32Message { 8 | repeated sint32 value = 1; 9 | } 10 | 11 | message Int32Message { 12 | repeated int32 value = 1; 13 | } -------------------------------------------------------------------------------- /26-grpc-2/taskmanager/api/taskmanager.go: -------------------------------------------------------------------------------- 1 | //go:generate protoc --go_out=./ --go_opt=paths=source_relative --go-grpc_out=./ --go-grpc_opt=paths=source_relative proto/taskmanager.proto 2 | 3 | package api 4 | -------------------------------------------------------------------------------- /26-grpc-2/taskmanager/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "taskmanager/api/proto" 7 | 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | func main() { 12 | conn, err := grpc.Dial(":50051", grpc.WithInsecure()) 13 | if err != nil { 14 | log.Fatalf("Could not connect: %v", err) 15 | } 16 | defer conn.Close() 17 | 18 | client := proto.NewTaskServiceClient(conn) 19 | 20 | // Create a new task 21 | createResponse, err := client.CreateTask(context.Background(), &proto.TaskRequest{ 22 | Title: "New Task", 23 | Description: "Description for new task", 24 | Status: "Pending", 25 | }) 26 | if err != nil { 27 | log.Fatalf("Error creating task: %v", err) 28 | } 29 | log.Printf("Task created: %v\n", createResponse) 30 | } 31 | -------------------------------------------------------------------------------- /26-grpc-2/taskmanager/go.mod: -------------------------------------------------------------------------------- 1 | module taskmanager 2 | 3 | go 1.19 4 | 5 | require google.golang.org/grpc v1.59.0 6 | 7 | require ( 8 | github.com/golang/protobuf v1.5.3 // indirect 9 | golang.org/x/net v0.14.0 // indirect 10 | golang.org/x/sys v0.11.0 // indirect 11 | golang.org/x/text v0.12.0 // indirect 12 | google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect 13 | google.golang.org/protobuf v1.31.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /26-grpc-2/taskmanager/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "google.golang.org/grpc/reflection" 5 | "log" 6 | "net" 7 | "taskmanager/api/proto" 8 | "taskmanager/internal/task" 9 | 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | func main() { 14 | lis, err := net.Listen("tcp", ":50051") 15 | if err != nil { 16 | log.Fatalf("Failed to listen: %v", err) 17 | } 18 | 19 | s := grpc.NewServer() 20 | taskService := task.NewService() 21 | taskHandler := task.NewHandler(taskService) 22 | 23 | proto.RegisterTaskServiceServer(s, taskHandler) 24 | // Register reflection service on gRPC server. 25 | reflection.Register(s) 26 | 27 | log.Println("Server is listening on port 50051...") 28 | if err := s.Serve(lis); err != nil { 29 | log.Fatalf("Failed to serve: %v", err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /26-http/client-func-method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log/slog" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | 11 | resp, err := http.Get("http://127.0.0.1:8080/stat") 12 | if err != nil { 13 | slog.Error("error sending request", "err", err) 14 | return 15 | } 16 | defer resp.Body.Close() // <-- Зачем? 17 | 18 | body, err := io.ReadAll(resp.Body) 19 | if err != nil { 20 | slog.Error("error reading response body", "err", err) 21 | return 22 | } 23 | 24 | slog.Info("responce body from stat", "body", body) 25 | } 26 | -------------------------------------------------------------------------------- /26-http/client-ws/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log/slog" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | 9 | "github.com/gorilla/websocket" 10 | "github.com/lmittmann/tint" 11 | ) 12 | 13 | func readLoop(c *websocket.Conn) { 14 | for { 15 | _, buff, err := c.ReadMessage() 16 | if err != nil { 17 | c.Close() 18 | break 19 | } 20 | slog.Info("got datagram", "content", string(buff)) 21 | } 22 | } 23 | 24 | func main() { 25 | slog.SetDefault(slog.New(tint.NewHandler(os.Stdout, nil))) 26 | 27 | ch := make(chan os.Signal, 1) 28 | signal.Notify(ch, syscall.SIGTERM) 29 | 30 | url := "ws://localhost:8080/stat-stream" 31 | wsDialer := websocket.Dialer{} 32 | conn, _, err := wsDialer.Dial(url, nil) 33 | if err != nil { 34 | slog.Error("error dialing", "err", err) 35 | return 36 | } 37 | 38 | go readLoop(conn) 39 | <-ch 40 | conn.Close() 41 | } 42 | -------------------------------------------------------------------------------- /26-http/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/26-http 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/gorilla/websocket v1.4.2 7 | github.com/stretchr/testify v1.7.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.0 // indirect 12 | github.com/lmittmann/tint v1.0.7 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /26-http/handler/handler_test.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "bytes" 5 | "github.com/stretchr/testify/require" 6 | "io" 7 | "net/http" 8 | "net/http/httptest" 9 | "testing" 10 | ) 11 | 12 | func TestService_SubmitVote(t *testing.T) { 13 | service := NewService() 14 | 15 | cases := []struct { 16 | name string 17 | method string 18 | target string 19 | body io.Reader 20 | responseCode int 21 | }{ 22 | {"bad_request", http.MethodPost, "http://test.test/vote", nil, http.StatusBadRequest}, 23 | { 24 | "ok", 25 | http.MethodPost, 26 | "http://test.test/vote", 27 | bytes.NewBufferString(`{"candidate_id": 1, "passport": "test"}`), 28 | http.StatusOK, 29 | }, 30 | } 31 | 32 | for _, c := range cases { 33 | t.Run(c.name, func(t *testing.T) { 34 | r := httptest.NewRequest(c.method, c.target, c.body) 35 | w := httptest.NewRecorder() 36 | service.SubmitVote(w, r) 37 | resp := w.Result() 38 | require.Equal(t, c.responseCode, resp.StatusCode) 39 | }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /26-http/middleware-abstract/abstract_middleware.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Processor — базовая функция‑обработчик. 4 | // В реальном приложении это может быть что угодно: работа с файлом, 5 | // запрос к БД, вычисления, отправка данных и т.д. 6 | // Принимает строку и возвращает строку. 7 | type Processor func(string) string 8 | 9 | // Middleware — функция‑обёртка над Processor. 10 | // Принимает "следующий" Processor и возвращает новый Processor, 11 | // выполняя дополнительные действия до и/или после вызова next. 12 | type Middleware func(Processor) Processor 13 | 14 | // Chain строит окончательный Processor, последовательно оборачивая исходный p 15 | // всеми middleware из списка. Middleware применяются в порядке передачи 16 | // (m1, m2, m3) → m1(next(m2(next(m3(p))))) 17 | func Chain(p Processor, mws ...Middleware) Processor { 18 | // Оборачиваем в обратном порядке, чтобы первый в списке выполнился первым 19 | for i := len(mws) - 1; i >= 0; i-- { 20 | p = mws[i](p) 21 | } 22 | return p 23 | } 24 | -------------------------------------------------------------------------------- /26-http/middleware-abstract/abstract_middleware_test.go: -------------------------------------------------------------------------------- 1 | // Этот тест демонстрирует, что цепочка выполняет middleware 2 | // в нужном порядке и выдаёт ожидаемый результат. 3 | 4 | package main 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // Echo — «голый» Processor без обёрток. 13 | func Echo(input string) string { 14 | return ">> " + input 15 | } 16 | 17 | func TestChain(t *testing.T) { 18 | wrapped := Chain(Echo, Trimmer, UpperCaser) 19 | 20 | got := wrapped(" hello ") 21 | want := ">> HELLO" 22 | 23 | assert.Equal(t, want, got) 24 | } 25 | 26 | func TestChainBlock(t *testing.T) { 27 | wrapped := Chain(Echo, Trimmer, Blocker, UpperCaser) 28 | 29 | got := wrapped(" hello ") 30 | want := "[blocked] hello" 31 | 32 | assert.Equal(t, want, got) 33 | } 34 | -------------------------------------------------------------------------------- /26-http/middleware/client.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | type LoggingRoundTripper struct { 9 | rt http.RoundTripper 10 | } 11 | 12 | func NewLoggingRoundTripper(rt http.RoundTripper) *LoggingRoundTripper { 13 | return &LoggingRoundTripper{ 14 | rt: rt, 15 | } 16 | } 17 | 18 | func (lrt *LoggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) { 19 | fmt.Printf("Sending request to %v\n", req.URL) 20 | 21 | res, err = lrt.rt.RoundTrip(req) 22 | 23 | if err != nil { 24 | fmt.Printf("Error: %v", err) 25 | } else { 26 | fmt.Printf("Received %v response\n", res.Status) 27 | } 28 | 29 | return 30 | } 31 | -------------------------------------------------------------------------------- /27-grpc/Makefile: -------------------------------------------------------------------------------- 1 | generate: 2 | rm -rf elections/pb 3 | mkdir -p elections/pb 4 | 5 | protoc \ 6 | --proto_path=api/elections/ \ 7 | --go_out=elections/pb \ 8 | --go-grpc_out=elections/pb \ 9 | api/elections/*.proto 10 | 11 | protoc \ 12 | --proto_path=api/elections-with-admin/ \ 13 | --go_out=elections-with-admin \ 14 | --go-grpc_out=elections-with-admin \ 15 | api/elections-with-admin/*.proto 16 | protoc \ 17 | --proto_path=api/elections-with-stats/ \ 18 | --go_out=elections-with-stats \ 19 | --go-grpc_out=elections-with-stats \ 20 | api/elections-with-stats/*.proto 21 | 22 | evans: 23 | evans --proto api/elections/elections.proto repl 24 | 25 | evans-stats: 26 | evans --proto api/elections-with-stats/elections.proto repl 27 | 28 | evans-admin: 29 | evans --proto api/elections-with-admin/elections.proto repl 30 | -------------------------------------------------------------------------------- /27-grpc/api/elections-with-admin/elections.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package elections_with_admin; 4 | option go_package = "./;main"; 5 | 6 | import "google/protobuf/timestamp.proto"; 7 | import "google/protobuf/empty.proto"; 8 | 9 | service Elections { 10 | rpc SubmitVote (Vote) returns (google.protobuf.Empty) {} 11 | rpc Internal (stream Vote) returns (stream StatsVote) {} 12 | } 13 | 14 | message Vote { 15 | string passport = 1; 16 | uint32 candidate_id = 2; 17 | string note = 3; 18 | google.protobuf.Timestamp time = 4; 19 | } 20 | 21 | message Stats { 22 | map records = 1; 23 | google.protobuf.Timestamp time = 2; 24 | } 25 | 26 | message StatsVote { 27 | oneof body { 28 | Stats stats = 1; 29 | Vote vote = 2; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /27-grpc/api/elections-with-stats/elections.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package elections_with_stat; 4 | option go_package = "./;main"; 5 | 6 | import "google/protobuf/timestamp.proto"; 7 | import "google/protobuf/empty.proto"; 8 | 9 | service Elections { 10 | rpc SubmitVote (Vote) returns (google.protobuf.Empty) {} 11 | rpc GetStats (google.protobuf.Empty) returns (stream Stats) {} 12 | } 13 | 14 | message Vote { 15 | string passport = 1; 16 | uint32 candidate_id = 2; 17 | string note = 3; 18 | google.protobuf.Timestamp time = 4; 19 | } 20 | 21 | message Stats { 22 | map records = 1; 23 | google.protobuf.Timestamp time = 2; 24 | } 25 | -------------------------------------------------------------------------------- /27-grpc/api/elections/elections.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package elections; 4 | option go_package = "./;pb"; 5 | 6 | import "google/protobuf/timestamp.proto"; 7 | 8 | service Elections { 9 | rpc SubmitVote (SubmitVoteRequest) returns (SubmitVoteResponse) {} 10 | } 11 | 12 | message SubmitVoteRequest { 13 | message Vote { 14 | string passport = 1; 15 | uint32 candidate_id = 2; 16 | string note = 3; 17 | google.protobuf.Timestamp time = 4; 18 | } 19 | 20 | Vote vote = 1; 21 | } 22 | 23 | message SubmitVoteResponse { 24 | } 25 | -------------------------------------------------------------------------------- /27-grpc/elections-with-admin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | func main() { 11 | lsn, err := net.Listen("tcp", ":50051") 12 | if err != nil { 13 | log.Fatal(err) 14 | } 15 | 16 | server := grpc.NewServer( 17 | grpc.ChainStreamInterceptor( 18 | StreamServerRequestValidatorInterceptor(ValidateReq), 19 | ), 20 | ) 21 | RegisterElectionsServer(server, NewService()) 22 | 23 | log.Printf("starting server on %s", lsn.Addr().String()) 24 | if err := server.Serve(lsn); err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /27-grpc/elections-with-stats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | func main() { 11 | lsn, err := net.Listen("tcp", ":50051") 12 | if err != nil { 13 | log.Fatal(err) 14 | } 15 | 16 | server := grpc.NewServer() 17 | RegisterElectionsServer(server, NewService()) 18 | 19 | log.Printf("starting server on %s", lsn.Addr().String()) 20 | if err := server.Serve(lsn); err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /27-grpc/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/27-grpc 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/golang/protobuf v1.5.2 7 | github.com/google/go-cmp v0.5.6 // indirect 8 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect 9 | golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect 10 | google.golang.org/genproto v0.0.0-20210607140030-00d4fb20b1ae // indirect 11 | google.golang.org/grpc v1.38.0 12 | google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 13 | google.golang.org/protobuf v1.26.0 14 | ) 15 | -------------------------------------------------------------------------------- /27-grpc/tools.go: -------------------------------------------------------------------------------- 1 | //+build tools 2 | 3 | package tools 4 | 5 | import ( 6 | "google.golang.org/grpc/cmd/protoc-gen-go-grpc" 7 | "google.golang.org/protobuf/cmd/protoc-gen-go" 8 | ) 9 | -------------------------------------------------------------------------------- /27-websockets/README.md: -------------------------------------------------------------------------------- 1 | Примеры реализации простейших вебсокет сервера/клиента на языке Golang. 2 | -------------------------------------------------------------------------------- /27-websockets/src/1/go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.13 4 | 5 | require github.com/gorilla/websocket v1.4.1 6 | -------------------------------------------------------------------------------- /27-websockets/src/1/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 2 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 3 | -------------------------------------------------------------------------------- /27-websockets/src/2/client/go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.13 4 | 5 | require github.com/gorilla/websocket v1.4.1 6 | -------------------------------------------------------------------------------- /27-websockets/src/2/client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 2 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 3 | -------------------------------------------------------------------------------- /27-websockets/src/2/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "log" 6 | "os" 7 | "time" 8 | 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | func runWriteLoop(conn *websocket.Conn, ch <-chan []byte) { 13 | for msg := range ch { 14 | conn.SetWriteDeadline(time.Now().Add(5 * time.Second)) 15 | if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil { 16 | log.Fatal(err) 17 | } 18 | log.Printf("message was sent") 19 | } 20 | } 21 | 22 | func main() { 23 | url := "ws://localhost:33333/ws?cid=101" 24 | wsDialer := websocket.Dialer{} 25 | conn, _, err := wsDialer.Dial(url, nil) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | 30 | ch := make(chan []byte) 31 | go runWriteLoop(conn, ch) 32 | 33 | reader := bufio.NewReader(os.Stdin) 34 | for { 35 | text, err := reader.ReadString('\n') 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | ch <- []byte(text) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /27-websockets/src/2/server/go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.13 4 | 5 | require github.com/gorilla/websocket v1.4.1 6 | -------------------------------------------------------------------------------- /27-websockets/src/2/server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= 2 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 3 | -------------------------------------------------------------------------------- /29-queues/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: rabbit 2 | 3 | rabbit: 4 | # http://localhost:15672/ guest:guest 5 | docker run -d --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management 6 | -------------------------------------------------------------------------------- /29-queues/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/29-queues 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cenkalti/backoff/v3 v3.2.2 7 | github.com/streadway/amqp v1.0.0 8 | ) 9 | -------------------------------------------------------------------------------- /29-queues/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= 2 | github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= 3 | github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= 4 | github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 5 | -------------------------------------------------------------------------------- /31-integration-testing/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: up down restart test 2 | 3 | up: 4 | docker-compose up -d --build 5 | 6 | down: 7 | docker-compose down 8 | 9 | restart: down up 10 | 11 | test: 12 | set -e ;\ 13 | docker-compose -f docker-compose.test.yml up --build -d ;\ 14 | test_status_code=0 ;\ 15 | docker-compose -f docker-compose.test.yml run integration_tests go test || test_status_code=$$? ;\ 16 | docker-compose -f docker-compose.test.yml down ;\ 17 | exit $$test_status_code ; 18 | 19 | test-cleanup: 20 | docker-compose -f docker-compose.test.yml down \ 21 | --rmi local \ 22 | --volumes \ 23 | --remove-orphans \ 24 | --timeout 60; \ 25 | docker-compose rm -f 26 | -------------------------------------------------------------------------------- /31-integration-testing/assets/user_reg_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OtusGolang/webinars_practical_part/230b215c0924a9a77528d9687ddc3a032b438593/31-integration-testing/assets/user_reg_event.png -------------------------------------------------------------------------------- /31-integration-testing/cmd/notification-service/Dockerfile: -------------------------------------------------------------------------------- 1 | # Environment 2 | FROM golang:1.14 as build-env 3 | 4 | RUN mkdir -p /opt/notify_service 5 | WORKDIR /opt/notify_service 6 | COPY go.mod . 7 | COPY go.sum . 8 | RUN go mod download 9 | 10 | COPY . . 11 | RUN CGO_ENABLED=0 go build -o /opt/service/notify_service 12 | 13 | # Release 14 | FROM alpine:latest 15 | 16 | COPY --from=build-env /opt/service/notify_service /bin/notify_service 17 | ENTRYPOINT ["/bin/notify_service"] 18 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/notification-service/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type AmqpConfig struct { 4 | AmqpDSN string `envconfig:"AMQP_DSN" required:"true"` 5 | QueueName string `envconfig:"QUEUE_NAME" default:"ToNotificationService"` 6 | RegExchangeName string `envconfig:"REG_EXCHANGE_NAME" default:"UserRegistrations"` 7 | NotifyExchangeName string `envconfig:"NOTIFY_EXCHANGE_NAME" default:"UserNotifications"` 8 | } 9 | 10 | type config struct { 11 | AmqpConfig 12 | } 13 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/notification-service/go.mod: -------------------------------------------------------------------------------- 1 | module notification_service 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/kelseyhightower/envconfig v1.4.0 7 | github.com/streadway/amqp v1.0.0 8 | ) 9 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/notification-service/go.sum: -------------------------------------------------------------------------------- 1 | github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= 2 | github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 3 | github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= 4 | github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 5 | github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= 6 | github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 7 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/registration-service/Dockerfile: -------------------------------------------------------------------------------- 1 | # Environment 2 | FROM golang:1.14 as build-env 3 | 4 | RUN mkdir -p /opt/reg_service 5 | WORKDIR /opt/reg_service 6 | COPY go.mod . 7 | COPY go.sum . 8 | RUN go mod download 9 | 10 | COPY . . 11 | RUN CGO_ENABLED=0 go build -o /opt/service/reg_service 12 | 13 | # Release 14 | FROM alpine:latest 15 | COPY --from=build-env /opt/service/reg_service /bin/reg_service 16 | ENTRYPOINT ["/bin/reg_service"] 17 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/registration-service/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type DbConfig struct { 4 | DbDriver string `envconfig:"DB_DRIVER" default:"postgres"` 5 | DbDSN string `envconfig:"DB_DSN" required:"true"` 6 | } 7 | 8 | type AmqpConfig struct { 9 | AmqpDSN string `envconfig:"AMQP_DSN" required:"true"` 10 | RegExchangeName string `envconfig:"REG_EXCHANGE_NAME" default:"UserRegistrations"` 11 | } 12 | 13 | type config struct { 14 | DbConfig 15 | AmqpConfig 16 | ServerAddr string `envconfig:"SERVER_ADDR" required:"true"` 17 | } 18 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/registration-service/db.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/jmoiron/sqlx" 4 | 5 | type user struct { 6 | FirstName string `json:"first_name" db:"first_name"` 7 | Email string `json:"email" db:"email"` 8 | Age uint8 `json:"age" db:"age"` 9 | } 10 | 11 | type sqlExecutor interface { 12 | sqlx.Ext 13 | NamedQuery(query string, arg interface{}) (*sqlx.Rows, error) 14 | } 15 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/registration-service/go.mod: -------------------------------------------------------------------------------- 1 | module registration_service 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/jmoiron/sqlx v1.3.1 7 | github.com/kelseyhightower/envconfig v1.4.0 8 | github.com/lib/pq v1.10.0 9 | github.com/streadway/amqp v1.0.0 10 | ) 11 | -------------------------------------------------------------------------------- /31-integration-testing/cmd/registration-service/rmq.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/streadway/amqp" 7 | ) 8 | 9 | type publisher interface { 10 | io.Closer 11 | amqp.Acknowledger 12 | Publish(exchange, key string, mandatory, immediate bool, msg amqp.Publishing) error 13 | } 14 | -------------------------------------------------------------------------------- /31-integration-testing/config.toml: -------------------------------------------------------------------------------- 1 | PSQL_DSN=${PSQL_DSN} 2 | 3 | #### Псевдокод 4 | env > config.toml 5 | 6 | 7 | ### 8 | local.env 9 | export PSQL_DSN="...." 10 | 11 | qa.env 12 | 13 | ### 14 | -------------------------------------------------------------------------------- /31-integration-testing/configs/rabbit.config: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | rabbit, 4 | [ 5 | { loopback_users, [] } 6 | ] 7 | }, 8 | { 9 | rabbitmq_management, 10 | [ 11 | { load_definitions, "/etc/rabbitmq/definitions.json" } 12 | ] 13 | } 14 | ]. 15 | -------------------------------------------------------------------------------- /31-integration-testing/scripts/setup.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | first_name VARCHAR(255) PRIMARY KEY, 3 | email VARCHAR(255) NOT NULL, 4 | age SMALLINT NOT NULL 5 | ); 6 | -------------------------------------------------------------------------------- /31-integration-testing/tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.16 2 | 3 | RUN mkdir -p /opt/integration_tests 4 | WORKDIR /opt/integration_tests 5 | 6 | COPY go.mod . 7 | COPY go.sum . 8 | RUN go mod download 9 | 10 | COPY . . 11 | CMD ["go", "test"] 12 | -------------------------------------------------------------------------------- /31-integration-testing/tests/features/notification.feature: -------------------------------------------------------------------------------- 1 | # file: features/notification.feature 2 | 3 | # http://localhost:8088/ 4 | # http://reg_service:8088/ 5 | 6 | Feature: Email notification sending 7 | As API client of registration service 8 | In order to understand that the user was informed about registration 9 | I want to receive event from notifications queue 10 | 11 | Scenario: Registration service is available 12 | When I send "GET" request to "http://reg_service:8088/" 13 | Then The response code should be 200 14 | And The response should match text "OK" 15 | 16 | Scenario: Notification event is received 17 | When I send "POST" request to "http://reg_service:8088/api/v1/registration" with "application/json" data: 18 | """ 19 | { 20 | "first_name": "otus", 21 | "email": "otus@otus.ru", 22 | "age": 27 23 | } 24 | """ 25 | Then The response code should be 200 26 | And I receive event with text "otus@otus.ru" 27 | -------------------------------------------------------------------------------- /31-integration-testing/tests/go.mod: -------------------------------------------------------------------------------- 1 | module godog_example/integration_tests 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cucumber/godog v0.12.0 7 | github.com/cucumber/messages-go/v16 v16.0.1 8 | github.com/streadway/amqp v1.0.0 9 | ) 10 | -------------------------------------------------------------------------------- /31-integration-testing/tests/main_test.go: -------------------------------------------------------------------------------- 1 | package scripts 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | "github.com/cucumber/godog" 10 | ) 11 | 12 | const delay = 5 * time.Second 13 | 14 | func TestMain(m *testing.M) { 15 | log.Printf("wait %s for service availability...", delay) 16 | time.Sleep(delay) 17 | 18 | status := godog.TestSuite{ 19 | Name: "integration", 20 | ScenarioInitializer: InitializeScenario, 21 | Options: &godog.Options{ 22 | Format: "progress", // Замените на "pretty" для лучшего вывода 23 | Paths: []string{"features"}, 24 | Randomize: 0, // Последовательный порядок исполнения 25 | }, 26 | }.Run() 27 | 28 | if st := m.Run(); st > status { 29 | status = st 30 | } 31 | os.Exit(status) 32 | } 33 | -------------------------------------------------------------------------------- /32-monitoring/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine 2 | 3 | WORKDIR /opt/app 4 | 5 | COPY go.sum go.sum 6 | COPY go.mod go.mod 7 | RUN go mod download 8 | 9 | COPY . . 10 | RUN go install . 11 | ENTRYPOINT /go/bin/32-monitoring 12 | 13 | EXPOSE 9091 14 | EXPOSE 9092 15 | -------------------------------------------------------------------------------- /32-monitoring/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: up 2 | 3 | up: 4 | docker-compose up 5 | 6 | cleanup: 7 | docker-compose down \ 8 | --rmi local \ 9 | --volumes \ 10 | --remove-orphans \ 11 | --timeout 60; \ 12 | docker-compose rm -f 13 | -------------------------------------------------------------------------------- /32-monitoring/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/32-monitoring 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/golang/protobuf v1.5.2 // indirect 7 | github.com/prometheus/client_golang v1.11.0 8 | github.com/prometheus/common v0.29.0 // indirect 9 | github.com/slok/go-http-metrics v0.9.0 10 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect 11 | google.golang.org/protobuf v1.27.1 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /32-monitoring/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/prometheus/client_golang/prometheus/promhttp" 8 | metrics "github.com/slok/go-http-metrics/metrics/prometheus" 9 | "github.com/slok/go-http-metrics/middleware" 10 | middlewarestd "github.com/slok/go-http-metrics/middleware/std" 11 | ) 12 | 13 | func myHandler(w http.ResponseWriter, _ *http.Request) { 14 | defer regCounter.Inc() 15 | 16 | w.WriteHeader(http.StatusOK) 17 | w.Write([]byte("hello world!")) 18 | } 19 | 20 | func main() { 21 | // Middleware для мониторинга 22 | mdlw := middleware.New(middleware.Config{ 23 | Recorder: metrics.NewRecorder(metrics.Config{}), 24 | }) 25 | h := middlewarestd.Handler("", mdlw, http.HandlerFunc(myHandler)) 26 | 27 | // HTTP exporter для prometheus 28 | go http.ListenAndServe(":9091", promhttp.Handler()) 29 | 30 | // Ваш основной HTTP сервис 31 | if err := http.ListenAndServe(":9092", h); err != nil { 32 | log.Panicf("error while serving: %s", err) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /32-monitoring/metrics.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/prometheus/client_golang/prometheus" 5 | ) 6 | 7 | var regCounter = prometheus.NewCounter(prometheus.CounterOpts{ 8 | Name: "business_registration", 9 | Help: "Client registration event", 10 | }) 11 | 12 | func init() { 13 | prometheus.MustRegister(regCounter) 14 | } 15 | -------------------------------------------------------------------------------- /32-monitoring/prometheus.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 5s 3 | external_labels: 4 | monitor: '32-monitoring-example' 5 | 6 | scrape_configs: 7 | - job_name: 'prometheus' 8 | static_configs: 9 | - targets: ['prometheus:9090'] 10 | 11 | - job_name: 'node' 12 | static_configs: 13 | - targets: ['node-exporter:9100'] 14 | 15 | - job_name: 'rest' 16 | static_configs: 17 | - targets: ['app:9091'] 18 | -------------------------------------------------------------------------------- /open-lesson/interfaces/02_refs/refs_test.go: -------------------------------------------------------------------------------- 1 | package refs 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type Speaker interface { 9 | SayHello() 10 | } 11 | 12 | type Human struct { 13 | Greeting string 14 | } 15 | 16 | func (h Human) SayHello() { // try reference receiver 17 | fmt.Println(h.Greeting) 18 | } 19 | 20 | func TestIfaceRefs(t *testing.T) { 21 | a := Human{Greeting: "Hello"} 22 | aref := &a 23 | 24 | var i1, i2 Speaker // interface 25 | 26 | i1 = a 27 | i2 = aref 28 | 29 | a.Greeting = "Updated text" 30 | 31 | a.SayHello() 32 | i1.SayHello() 33 | i2.SayHello() 34 | 35 | // {Updated text} 36 | // {Hello} 37 | // &{Updated text} 38 | 39 | after1 := i1.(Human) 40 | after2 := i2.(*Human) 41 | 42 | fmt.Println(after1, after2) // {Hello} &{Updated text} 43 | 44 | // i1: iface.data = copy 45 | // i2: iface.data = reference 46 | 47 | } 48 | -------------------------------------------------------------------------------- /open-lesson/interfaces/03_receivers/dark_test.go: -------------------------------------------------------------------------------- 1 | package receivers 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | func dark_magic(i any) { 9 | p := (*struct { // iface mock 10 | tab unsafe.Pointer // itab mock 11 | data unsafe.Pointer 12 | })(unsafe.Pointer(&i)) 13 | 14 | fmt.Printf("iface: {itab: %x, data: %x}\n", p.tab, p.data) 15 | } 16 | -------------------------------------------------------------------------------- /open-lesson/interfaces/04_type_assertion/type_assertion_test.go: -------------------------------------------------------------------------------- 1 | package typeassertion 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestTypeAssertion(t *testing.T) { 9 | var i any = "hello" // any = interface{} 10 | 11 | r1 := i.(int) 12 | fmt.Println(r1) 13 | 14 | r2, ok := i.(string) 15 | fmt.Println(r2, ok) 16 | 17 | r3, ok := i.(fmt.Stringer) 18 | fmt.Println(r3, ok) 19 | 20 | r4, ok := i.(float64) 21 | fmt.Println(r4, ok) 22 | } 23 | -------------------------------------------------------------------------------- /open-lesson/interfaces/05_type_switch/type_switch_test.go: -------------------------------------------------------------------------------- 1 | package typeswitch 2 | 3 | import "testing" 4 | 5 | type MsgUserBalanceChanged struct { 6 | userID string 7 | balance string 8 | } 9 | 10 | type MsgEventChanged struct { 11 | eventID string 12 | } 13 | 14 | func processMessage(msg interface{}) { 15 | // Implement me. 16 | } 17 | 18 | /* 19 | Required output: 20 | user "user-1" balance was changed to "1000" 21 | event "event-1" was changed 22 | unknown message: unknown 23 | */ 24 | func TestProcessMessage(t *testing.T) { 25 | processMessage(MsgUserBalanceChanged{"user-1", "1000"}) 26 | processMessage(MsgEventChanged{"event-1"}) 27 | processMessage("unknown") 28 | } 29 | -------------------------------------------------------------------------------- /open-lesson/interfaces/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/OtusGolang/webinars_practical_part/open-lesson/receivers 2 | 3 | go 1.24 4 | --------------------------------------------------------------------------------