├── .DS_Store
├── .gitignore
├── .vscode
└── launch.json
├── Design-patterns-for-asynchronous-API-communication.md
├── LICENSE
├── MISTAKE.md
├── README.md
├── README_VI.md
├── WIREMOCK.md
├── aws
├── .DS_Store
├── apigw
│ ├── README.md
│ └── mtls
│ │ ├── RootCA.key
│ │ ├── RootCA.pem
│ │ ├── my_client.csr
│ │ ├── my_client.key
│ │ └── my_client.pem
├── cloudfront-func
│ ├── README.md
│ └── kvs-hmac-sha256
│ │ ├── README.md
│ │ ├── signature.js
│ │ └── test-objects
│ │ └── valid-hmac.json
├── cloudwatch
│ ├── README.md
│ └── logGroup
│ │ ├── README.md
│ │ └── main.go
├── codeartifact
│ └── README.md
├── codecommit
│ └── README.md
├── lambda
│ ├── .DS_Store
│ ├── CRUD_POSTGRES.md
│ ├── README.md
│ ├── courses
│ │ └── sharing
│ │ │ ├── .gitignore
│ │ │ ├── Makefile
│ │ │ ├── hello
│ │ │ └── main.go
│ │ │ ├── serverless.yml
│ │ │ └── world
│ │ │ └── main.go
│ ├── crud
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.MD
│ │ ├── create
│ │ │ └── main.go
│ │ ├── delete
│ │ │ └── main.go
│ │ ├── models
│ │ │ └── user.go
│ │ ├── pkg
│ │ │ └── db.go
│ │ ├── read
│ │ │ └── main.go
│ │ ├── serverless.yml
│ │ ├── sql.sql
│ │ └── update
│ │ │ └── main.go
│ ├── golang-migration-go1.x-provided.al2
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── bootstrap
│ │ ├── migration
│ │ │ └── main.go
│ │ └── serverless.yml
│ ├── hello-api
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── hello
│ │ │ └── main.go
│ │ └── serverless.yml
│ ├── images
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── functions
│ │ │ ├── authorizer
│ │ │ │ ├── authorizer.yml
│ │ │ │ └── openapi-lambda-auth.py
│ │ │ ├── getImage
│ │ │ │ ├── main.go
│ │ │ │ └── validator.json
│ │ │ └── insertImage
│ │ │ │ ├── main.go
│ │ │ │ └── validator.json
│ │ └── serverless.yml
│ ├── lambda-go-1-2
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.MD
│ │ ├── hello
│ │ │ └── main.go
│ │ ├── serverless.yml
│ │ └── world
│ │ │ └── main.go
│ └── lambda-go-3
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.MD
│ │ ├── create
│ │ └── main.go
│ │ ├── delete
│ │ └── main.go
│ │ ├── models
│ │ └── user.go
│ │ ├── pkg
│ │ └── db.go
│ │ ├── read
│ │ └── main.go
│ │ ├── serverless.yml
│ │ ├── sql.sql
│ │ └── update
│ │ └── main.go
├── s3
│ ├── README.md
│ ├── delete.go
│ ├── error.html
│ ├── image
│ │ ├── handler-upload.png
│ │ ├── upload-success-s3.png
│ │ └── upload.png
│ ├── index.html
│ ├── s3.go
│ └── upload.go
├── secretsmanager
│ └── README.md
├── sqs
│ ├── README.md
│ ├── README_VI.md
│ ├── lambda
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.MD
│ │ ├── push
│ │ │ └── main.go
│ │ ├── receive
│ │ │ └── main.go
│ │ └── serverless.yml
│ ├── main.go
│ └── sqs.go
└── textract
│ └── main.go
├── concurrency
├── README.md
├── errorHandling.go
├── fanInfanOut.go
├── leak.go
├── patterns
│ ├── README.md
│ ├── fanInfanOut
│ │ └── main.go
│ ├── pipeline
│ │ └── main.go
│ ├── pubSub
│ │ └── main.go
│ ├── rateLimit
│ │ └── main.go
│ ├── selectTimeout
│ │ └── main.go
│ ├── semaphore
│ │ └── main.go
│ └── workerpool
│ │ └── main.go
├── preventLeak.go
├── selectStatement.go
├── singleflight
│ ├── main.go
│ └── output.png
└── syncCond.go
├── database
└── index
│ ├── README.md
│ └── note.txt
├── dtm
├── .gitignore
├── dtm-cases
│ ├── .gitignore
│ ├── LICENSE
│ ├── README-cn.md
│ ├── README.md
│ ├── cache
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ ├── demo
│ │ │ ├── api-atomic.go
│ │ │ ├── api-downgrade.go
│ │ │ ├── api-shared.go
│ │ │ ├── api-strong.go
│ │ │ ├── api-version.go
│ │ │ ├── data.go
│ │ │ └── main.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── main.go
│ │ └── table.sql
│ ├── flash
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── order
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ ├── common
│ │ │ └── common.go
│ │ ├── conf
│ │ │ └── conf.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── main.go
│ │ ├── order.sql
│ │ └── service
│ │ │ ├── api.go
│ │ │ ├── coupon.go
│ │ │ ├── order.go
│ │ │ ├── pay.go
│ │ │ ├── stock.go
│ │ │ └── types.go
│ └── utils
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── utils.go
├── dtm-examples
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── busi
│ │ ├── barrier.go
│ │ ├── base_grpc.go
│ │ ├── base_http.go
│ │ ├── base_jrpc.go
│ │ ├── base_types.go
│ │ ├── busi.pb.go
│ │ ├── busi.proto
│ │ ├── busi_grpc.pb.go
│ │ ├── data.go
│ │ ├── quick_start.go
│ │ ├── startup.go
│ │ └── utils.go
│ ├── doc
│ │ ├── README-cn.md
│ │ └── README-en.md
│ ├── dtmutil
│ │ ├── consts.go
│ │ ├── db.go
│ │ └── utils.go
│ ├── examples
│ │ ├── grpc_headers.go
│ │ ├── grpc_msg.go
│ │ ├── grpc_saga.go
│ │ ├── grpc_saga_barrier.go
│ │ ├── grpc_saga_other.go
│ │ ├── grpc_tcc.go
│ │ ├── grpc_workflow_mixed.go
│ │ ├── grpc_workflow_saga.go
│ │ ├── grpc_workflow_tcc.go
│ │ ├── grpc_xa.go
│ │ ├── http_barrier_redis.go
│ │ ├── http_headers.go
│ │ ├── http_more.go
│ │ ├── http_msg.go
│ │ ├── http_saga.go
│ │ ├── http_saga_barrier.go
│ │ ├── http_saga_gorm_barrier.go
│ │ ├── http_saga_mongo.go
│ │ ├── http_saga_mutidb.go
│ │ ├── http_saga_redis.go
│ │ ├── http_tcc.go
│ │ ├── http_tcc_barrier.go
│ │ ├── http_workflow_saga.go
│ │ ├── http_workflow_tcc.go
│ │ ├── http_workflow_xa.go
│ │ ├── http_xa.go
│ │ ├── http_xa_gorm.go
│ │ ├── startup.go
│ │ └── utils.go
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── sync-from-dtm.sh
├── dtm-lab
│ ├── LICENSE
│ ├── README.md
│ ├── dtmcli
│ │ ├── barrier.go
│ │ ├── barrier_mongo.go
│ │ ├── barrier_redis.go
│ │ ├── consts.go
│ │ ├── dtmimp
│ │ │ ├── README-cn.md
│ │ │ ├── README.md
│ │ │ ├── consts.go
│ │ │ ├── db_special.go
│ │ │ ├── trans_base.go
│ │ │ ├── trans_xa_base.go
│ │ │ ├── types.go
│ │ │ ├── utils.go
│ │ │ └── vars.go
│ │ ├── logger
│ │ │ └── logger.go
│ │ ├── trans_msg.go
│ │ ├── trans_saga.go
│ │ ├── trans_tcc.go
│ │ ├── types.go
│ │ ├── utils.go
│ │ └── xa.go
│ ├── dtmgrpc
│ │ ├── barrier.go
│ │ ├── dtmgimp
│ │ │ ├── README-cn.md
│ │ │ ├── README.md
│ │ │ ├── grpc_clients.go
│ │ │ ├── types.go
│ │ │ └── utils.go
│ │ ├── dtmgpb
│ │ │ ├── dtmgimp.pb.go
│ │ │ ├── dtmgimp.proto
│ │ │ └── dtmgimp_grpc.pb.go
│ │ ├── msg.go
│ │ ├── options.go
│ │ ├── saga.go
│ │ ├── tcc.go
│ │ ├── type.go
│ │ └── xa.go
│ ├── dummy.go
│ ├── go.mod
│ ├── go.sum
│ └── workflow
│ │ ├── dummyReadCloser.go
│ │ ├── factory.go
│ │ ├── imp.go
│ │ ├── rpc.go
│ │ ├── server.go
│ │ ├── utils.go
│ │ ├── wfpb
│ │ ├── wf.pb.go
│ │ ├── wf.proto
│ │ └── wf_grpc.pb.go
│ │ └── workflow.go
├── dtm
│ ├── .github
│ │ └── workflows
│ │ │ ├── codeql-analysis.yml
│ │ │ ├── docker.yml
│ │ │ ├── release.yml
│ │ │ └── tests.yml
│ ├── .gitignore
│ ├── LICENSE
│ ├── Makefile
│ ├── README.md
│ ├── admin
│ │ ├── .env
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── public
│ │ │ └── favicon.ico
│ │ ├── src
│ │ │ ├── App.vue
│ │ │ ├── api
│ │ │ │ └── api_dtm.ts
│ │ │ ├── assets
│ │ │ │ └── css
│ │ │ │ │ └── index.css
│ │ │ ├── components.d.ts
│ │ │ ├── components
│ │ │ │ ├── Screenfull
│ │ │ │ │ └── index.vue
│ │ │ │ └── SvgIcon
│ │ │ │ │ └── index.vue
│ │ │ ├── icons
│ │ │ │ ├── readme.md
│ │ │ │ └── svg
│ │ │ │ │ ├── fullscreen.svg
│ │ │ │ │ └── logo.svg
│ │ │ ├── layout
│ │ │ │ ├── aside.vue
│ │ │ │ ├── components
│ │ │ │ │ ├── content.vue
│ │ │ │ │ ├── header.vue
│ │ │ │ │ └── sidebar.vue
│ │ │ │ └── index.vue
│ │ │ ├── main.ts
│ │ │ ├── permission.ts
│ │ │ ├── router
│ │ │ │ ├── asyncRouter.ts
│ │ │ │ └── index.ts
│ │ │ ├── store
│ │ │ │ ├── index.ts
│ │ │ │ └── modules
│ │ │ │ │ └── layout.ts
│ │ │ ├── type
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── shim.vue.d.ts
│ │ │ │ └── store
│ │ │ │ │ └── layout.ts
│ │ │ ├── utils
│ │ │ │ ├── request.ts
│ │ │ │ └── util.ts
│ │ │ └── views
│ │ │ │ └── Dashboard
│ │ │ │ ├── GlobalTransactions
│ │ │ │ ├── AllTransactions.vue
│ │ │ │ ├── DialogTransactionDetail.vue
│ │ │ │ └── UnfinishedTransactions.vue
│ │ │ │ ├── KVPairs
│ │ │ │ ├── Topics.vue
│ │ │ │ └── _Components
│ │ │ │ │ ├── DialogTopicDetail.vue
│ │ │ │ │ └── DialogTopicSubscribe.vue
│ │ │ │ └── Nodes
│ │ │ │ └── LivingNodes.vue
│ │ ├── tailwind.config.js
│ │ ├── tsconfig.json
│ │ ├── vite.config.ts
│ │ └── yarn.lock
│ ├── charts
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── README.md
│ │ ├── templates
│ │ │ ├── NOTES.txt
│ │ │ ├── _helpers.tpl
│ │ │ ├── configmap.yaml
│ │ │ ├── deployment.yaml
│ │ │ ├── hpa.yaml
│ │ │ ├── ingress.yaml
│ │ │ ├── service.yaml
│ │ │ └── tests
│ │ │ │ └── test-connection.yaml
│ │ └── values.yaml
│ ├── client
│ │ ├── README.md
│ │ ├── dtmcli
│ │ │ ├── barrier.go
│ │ │ ├── barrier_mongo.go
│ │ │ ├── barrier_redis.go
│ │ │ ├── consts.go
│ │ │ ├── cover_test.go
│ │ │ ├── dtmimp
│ │ │ │ ├── README-cn.md
│ │ │ │ ├── README.md
│ │ │ │ ├── consts.go
│ │ │ │ ├── db_special.go
│ │ │ │ ├── db_special_test.go
│ │ │ │ ├── trans_base.go
│ │ │ │ ├── trans_xa_base.go
│ │ │ │ ├── types.go
│ │ │ │ ├── types_test.go
│ │ │ │ ├── utils.go
│ │ │ │ ├── utils_test.go
│ │ │ │ └── vars.go
│ │ │ ├── logger
│ │ │ │ └── logger.go
│ │ │ ├── trans_msg.go
│ │ │ ├── trans_saga.go
│ │ │ ├── trans_tcc.go
│ │ │ ├── types.go
│ │ │ ├── types_test.go
│ │ │ ├── utils.go
│ │ │ └── xa.go
│ │ ├── dtmgrpc
│ │ │ ├── barrier.go
│ │ │ ├── dtmgimp
│ │ │ │ ├── README-cn.md
│ │ │ │ ├── README.md
│ │ │ │ ├── grpc_clients.go
│ │ │ │ ├── types.go
│ │ │ │ └── utils.go
│ │ │ ├── dtmgpb
│ │ │ │ ├── dtmgimp.pb.go
│ │ │ │ ├── dtmgimp.proto
│ │ │ │ └── dtmgimp_grpc.pb.go
│ │ │ ├── msg.go
│ │ │ ├── options.go
│ │ │ ├── options_test.go
│ │ │ ├── saga.go
│ │ │ ├── tcc.go
│ │ │ ├── type.go
│ │ │ ├── type_test.go
│ │ │ └── xa.go
│ │ └── workflow
│ │ │ ├── dummyReadCloser.go
│ │ │ ├── factory.go
│ │ │ ├── imp.go
│ │ │ ├── rpc.go
│ │ │ ├── server.go
│ │ │ ├── utils.go
│ │ │ ├── wfpb
│ │ │ ├── wf.pb.go
│ │ │ ├── wf.proto
│ │ │ └── wf_grpc.pb.go
│ │ │ ├── workflow.go
│ │ │ └── workflow_test.go
│ ├── conf.sample.yml
│ ├── dtmsvr
│ │ ├── api.go
│ │ ├── api_grpc.go
│ │ ├── api_http.go
│ │ ├── api_json_rpc.go
│ │ ├── config
│ │ │ ├── config.go
│ │ │ ├── config_test.go
│ │ │ └── config_utils.go
│ │ ├── cron.go
│ │ ├── entry
│ │ │ └── main.go
│ │ ├── metrics.go
│ │ ├── microservices
│ │ │ └── drivers.go
│ │ ├── storage
│ │ │ ├── boltdb
│ │ │ │ ├── boltdb.go
│ │ │ │ └── boltdb_test.go
│ │ │ ├── redis
│ │ │ │ └── redis.go
│ │ │ ├── registry
│ │ │ │ ├── factory.go
│ │ │ │ └── registry.go
│ │ │ ├── sql
│ │ │ │ └── sql.go
│ │ │ ├── store.go
│ │ │ └── trans.go
│ │ ├── svr.go
│ │ ├── topics.go
│ │ ├── trans_class.go
│ │ ├── trans_process.go
│ │ ├── trans_status.go
│ │ ├── trans_type_msg.go
│ │ ├── trans_type_saga.go
│ │ ├── trans_type_tcc.go
│ │ ├── trans_type_workflow.go
│ │ ├── trans_type_xa.go
│ │ ├── utils.go
│ │ └── utils_test.go
│ ├── dtmutil
│ │ ├── consts.go
│ │ ├── db.go
│ │ ├── utils.go
│ │ └── utils_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── helper
│ │ ├── .goreleaser.yml
│ │ ├── Dockerfile-release
│ │ ├── README-cn.md
│ │ ├── README-en.md
│ │ ├── bench
│ │ │ ├── Makefile
│ │ │ ├── main.go
│ │ │ ├── prepare.sh
│ │ │ ├── setup-redis6.sh
│ │ │ ├── setup.sh
│ │ │ ├── svr
│ │ │ │ └── http.go
│ │ │ ├── test-boltdb.sh
│ │ │ ├── test-flash-sales.sh
│ │ │ ├── test-mysql.sh
│ │ │ └── test-redis.sh
│ │ ├── compose.store.yml
│ │ ├── golint.sh
│ │ ├── sync-client.sh
│ │ └── test-cover.sh
│ ├── main.go
│ ├── qs
│ │ └── main.go
│ ├── revive.toml
│ ├── sqls
│ │ ├── busi.mongo.js
│ │ ├── busi.mysql.sql
│ │ ├── busi.postgres.sql
│ │ ├── dtmcli.barrier.mongo.js
│ │ ├── dtmcli.barrier.mysql.sql
│ │ ├── dtmcli.barrier.postgres.sql
│ │ ├── dtmsvr.storage.mysql.sql
│ │ ├── dtmsvr.storage.postgres.sql
│ │ ├── dtmsvr.storage.sqlserver.sql
│ │ └── dtmsvr.storage.tdsql.sql
│ └── test
│ │ ├── api_test.go
│ │ ├── base_test.go
│ │ ├── busi
│ │ ├── barrier.go
│ │ ├── base_grpc.go
│ │ ├── base_http.go
│ │ ├── base_jrpc.go
│ │ ├── base_types.go
│ │ ├── busi.pb.go
│ │ ├── busi.proto
│ │ ├── busi_grpc.pb.go
│ │ ├── data.go
│ │ ├── quick_start.go
│ │ ├── startup.go
│ │ └── utils.go
│ │ ├── common_test.go
│ │ ├── dtmsvr_test.go
│ │ ├── main_test.go
│ │ ├── msg_barrier_mongo_test.go
│ │ ├── msg_barrier_redis_test.go
│ │ ├── msg_barrier_test.go
│ │ ├── msg_delay_test.go
│ │ ├── msg_grpc_barrier_redis_test.go
│ │ ├── msg_grpc_barrier_test.go
│ │ ├── msg_grpc_test.go
│ │ ├── msg_jrpc_test.go
│ │ ├── msg_options_test.go
│ │ ├── msg_test.go
│ │ ├── msg_webhook_test.go
│ │ ├── saga_barrier_mongo_test.go
│ │ ├── saga_barrier_redis_test.go
│ │ ├── saga_barrier_test.go
│ │ ├── saga_compatible_test.go
│ │ ├── saga_concurrent_test.go
│ │ ├── saga_grpc_barrier_test.go
│ │ ├── saga_grpc_test.go
│ │ ├── saga_options_test.go
│ │ ├── saga_test.go
│ │ ├── store_test.go
│ │ ├── tcc_barrier_test.go
│ │ ├── tcc_cover_test.go
│ │ ├── tcc_grpc_cover_test.go
│ │ ├── tcc_grpc_test.go
│ │ ├── tcc_jrpc_test.go
│ │ ├── tcc_old_test.go
│ │ ├── tcc_test.go
│ │ ├── topic_test.go
│ │ ├── types.go
│ │ ├── workflow_base_test.go
│ │ ├── workflow_grpc_test.go
│ │ ├── workflow_http_ret_test.go
│ │ ├── workflow_http_test.go
│ │ ├── workflow_interceptor_test.go
│ │ ├── workflow_ongoing_test.go
│ │ ├── workflow_xa_test.go
│ │ ├── xa_cover_test.go
│ │ ├── xa_grpc_test.go
│ │ └── xa_test.go
├── quick-start-sample
│ ├── .gitignore
│ ├── LICENSE
│ ├── README-cn.md
│ ├── README.md
│ ├── busi
│ │ ├── busi.pb.go
│ │ ├── busi.proto
│ │ ├── busi_grpc.pb.go
│ │ └── busi_server.go
│ ├── dtmcli-qs
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ └── main.go
│ ├── dtmgrpc-qs
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ └── main.go
│ ├── dummy.go
│ ├── go.mod
│ ├── go.sum
│ ├── workflow-grpc
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ └── main.go
│ └── workflow-http
│ │ ├── README-cn.md
│ │ ├── README.md
│ │ └── main.go
└── sql_dtm.sql
├── elsticsearch
├── README.md
├── main.go
└── query
│ ├── add.go
│ └── search.go
├── gin-web-framework
├── README.md
├── apiExample
│ └── index.go
└── main.go
├── go.mod
├── go.sum
├── http
├── keep-alive
│ ├── README.md
│ ├── client
│ │ └── client.go
│ └── server.go
├── request
│ └── http.go
├── retry
│ ├── README.md
│ └── main.go
└── reuse-http
│ └── main.go
├── interview
└── devops
│ ├── DevOps__1718418692.pdf
│ └── README.md
├── kafka
├── .DS_Store
├── README.md
├── README_VI.md
├── consumer-rebalance
│ ├── README_VI.md
│ ├── consumer.md
│ ├── consumer
│ │ └── main.go
│ └── producer
│ │ └── main.go
├── consumer
│ └── main.go
├── images
│ ├── at_least_once_delivery.png
│ ├── at_most_once_delivery.png
│ ├── consumer_group.png
│ ├── segment.png
│ ├── segment1.png
│ ├── segment2.png
│ └── segment3.png
├── mskaws
│ ├── README.md
│ └── main.go
└── producer
│ └── main.go
├── letgo
├── .DS_Store
├── README.md
├── chapter2.3
│ ├── README.md
│ ├── code.png
│ ├── main.go
│ ├── readme.png
│ └── web.png
├── chapter2.4
│ ├── README.md
│ ├── create_user.png
│ ├── list_user.png
│ ├── main.go
│ └── page_not_found.png
└── chapter2.9
│ ├── README.md
│ ├── code.png
│ ├── css_code.png
│ ├── folder.png
│ ├── main.go
│ ├── static_file.png
│ └── ui
│ ├── efs.go
│ ├── html
│ ├── base.tmpl
│ ├── pages
│ │ ├── create.tmpl
│ │ ├── home.tmpl
│ │ ├── login.tmpl
│ │ ├── signup.tmpl
│ │ └── view.tmpl
│ └── partials
│ │ └── nav.tmpl
│ └── static
│ ├── css
│ └── main.css
│ ├── img
│ ├── favicon.ico
│ └── logo.png
│ └── js
│ └── main.js
├── main.go
├── performances
├── README.MD
└── standard
│ ├── condition_test.go
│ ├── convert.go
│ ├── convert_test.go
│ └── pointer_test.go
├── redis
├── README.md
├── cluster.yaml
├── cluster
│ ├── 7000
│ │ └── redis.conf
│ ├── 7001
│ │ └── redis.conf
│ ├── 7002
│ │ └── redis.conf
│ ├── 7003
│ │ └── redis.conf
│ ├── 7004
│ │ └── redis.conf
│ ├── 7005
│ │ └── redis.conf
│ ├── README.md
│ └── docker-compose.yml
├── custom-values.yaml
├── library.yaml
├── main.go
├── master_replica.yaml
├── network.yaml
├── pipeline
│ ├── README.md
│ ├── README_VI.md
│ ├── range.go
│ └── range_test.go
├── pubsub
│ ├── README.md
│ ├── pub
│ │ └── main.go
│ └── sub
│ │ └── main.go
├── queue
│ ├── consumer
│ │ └── main.go
│ └── producer
│ │ └── main.go
├── redisPkg
│ └── connect.go
├── single.yaml
├── test.json
├── test.txt
└── test.yaml
├── rewinding_2024.md
├── structure
└── structure.md
├── terraform
├── README.md
└── apps
│ ├── .gitignore
│ ├── apigw
│ ├── README.md
│ ├── apikey.tf
│ ├── deployment.tf
│ ├── integration.tf
│ ├── main.tf
│ ├── method.tf
│ ├── resource.tf
│ ├── restapi.tf
│ ├── stage.tf
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ ├── usageplan.tf
│ └── variables.tf
│ ├── apigw_thien
│ ├── apikey.tf
│ ├── integration.tf
│ ├── main.tf
│ ├── method.tf
│ ├── resource.tf
│ ├── usageplan.tf
│ └── variables.tf
│ ├── lambda
│ └── main.tf
│ ├── sqs
│ ├── main.tf
│ ├── queuefifo.tf
│ └── variables.tf
│ ├── ssm
│ ├── main.tf
│ ├── paramter.tf
│ └── variables.tf
│ └── vpc
│ ├── main.tf
│ ├── subnet.tf
│ ├── terraform.tfstate
│ ├── terraform.tfstate.backup
│ ├── variables.tf
│ └── vpc.tf
├── tls
└── base64parse
│ ├── README.md
│ ├── certificate_base64.txt
│ ├── file.key
│ ├── file.pem
│ └── main.go
├── tranning
└── README.md
└── usecase
├── README.md
├── automatic
└── main.go
├── blake
├── 2b.go
├── 2b_test.go
├── 2s.go
├── 2s_test.go
└── main.go
├── context
├── README.md
├── cancel.go
├── deadline.go
├── package.go
└── timeout.go
├── crypto-demo
├── README.md
├── blake
│ ├── 2b.go
│ └── 2s.go
├── main.go
├── main_test.go
├── md5
│ └── md5.go
└── sha
│ └── sha1.go
├── defer
└── main.go
├── ecdsa
└── ecdsa.go
├── environment
├── README.MD
├── dev.yaml
├── envyaml.go
└── prod.yaml
├── file
├── main.go
└── s3
│ └── main.go
├── function
├── README.md
└── variadic.go
├── images
└── resizeImage.png
├── json
├── README.md
├── main.go
└── output.json
├── jwttoken
├── README.md
└── parse.go
├── loadbalancer
└── main.go
├── map
├── .DS_Store
├── p1
│ ├── main.go
│ ├── main_test.go
│ ├── map_1.1.png
│ └── map_1.2.png
├── p2
│ ├── main.go
│ ├── main_test.go
│ ├── map_2.1.png
│ ├── map_2.2.png
│ └── map_2.3.png
├── p3
│ ├── main.go
│ ├── main_test.go
│ ├── map_3.1.png
│ ├── map_3.2.png
│ ├── map_3.3.png
│ └── map_3.4.png
└── p4
│ ├── golang_map_4.1.png
│ ├── golang_map_4.2.png
│ ├── golang_map_4.3.png
│ └── main.go
├── password
└── main.go
├── resizeImage.go
├── rsa
├── README.md
├── REAME.md
└── gen.go
├── strings
├── main.go
└── main_test.go
└── time
├── README.md
├── profile001.png
├── profile002.png
├── profile003.png
├── profile004.png
├── profile005.png
├── profile006.png
├── profile007.png
├── tick.go
├── tickHour.png
├── tickNano-2.png
├── tickNano-3.png
├── tickNano-4.png
├── tickNano.png
├── tickSecond-2.png
└── tickSecond.png
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | vendor/
16 |
17 | .DS_Store
18 |
19 |
20 | aws/cloudfront-func/amazon-cloudfront-functions
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch Package",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "args": [
13 | "http_msg_doAndCommit"
14 | ],
15 | "program": "${workspaceFolder}/usecase/dtm/dtm-cases/flash/main.go"
16 | // "program": "${workspaceFolder}/usecase/dtm/quick-start-sample/workflow-http/main.go"
17 |
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/WIREMOCK.md:
--------------------------------------------------------------------------------
1 | # wire mock
2 |
3 | - run docker:
4 | ```sh
5 | docker run -it -d -p 8080:8080 --name wiremock holomekc/wiremock-gui
6 | ```
7 |
8 | - open ui:
9 | ```txt
10 | http://localhost:8080/__admin/webapp
11 | ```
12 |
13 | - create url:
14 | link: https://www.youtube.com/watch?v=MtWftxcvbjs
--------------------------------------------------------------------------------
/aws/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/.DS_Store
--------------------------------------------------------------------------------
/aws/apigw/README.md:
--------------------------------------------------------------------------------
1 | # apigw
2 | ## setup mtls
3 |
--------------------------------------------------------------------------------
/aws/apigw/mtls/my_client.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIIChjCCAW4CAQAwQTELMAkGA1UEBhMCdm4xEjAQBgNVBAgMCWhvY2hpbWluaDEP
3 | MA0GA1UEBwwGdGh1ZHVjMQ0wCwYDVQQKDARoZHNzMIIBIjANBgkqhkiG9w0BAQEF
4 | AAOCAQ8AMIIBCgKCAQEA0nfwcb0n+0LD14ExzL1TP6ydGvKA4bclXE7hBGsI5B+r
5 | VGHGvlAx3S7Te+S9ilDgPv58InAyZdF/BPCltCMD6da1Kb8XmMQLQcmbyLaXEpj6
6 | PwUsiRVBQ3HnaVFygLKpHOMH9PgMqeD2/rWLGp5rkp4SDzhvTR4ijaTaWVmj2yXk
7 | oPeaCsoVapLelHobLdiXzuqWifvp3yoDZPYrZsI0p+m/W0rhHEkT7S7VF39ECn2D
8 | wOM0j/aOqwxMy4bqndmOYDMZfrBV2nl5XnoSEoMH+dtdZu9lyHefhJGXxPF2b98D
9 | LE78hjZfqHamsKkRDVG2J9UCqz6yUZze0Kr5NcSgbQIDAQABoAAwDQYJKoZIhvcN
10 | AQELBQADggEBAHjFdS/QyTGAOMjyuChy0oW+jjH4t8Qr8DtPN0gTZ+jripE5aAsc
11 | Rbyt+K6/swQFoqc3DYIdkeU+1ZEouXFLMy/zQPXWRwlI515qifNzLuKbfqBJ6VI+
12 | BQM2NO4td6hgRHeAKv89tViroWxNk1jwGWCfPrkPlCtXVQR7riZYLY+tDFqPHEsu
13 | XSypYRGOxqFzTgcNY52dIgYzi/eFr/9xnVeAxaVLXT8UG7cazYacQ/sYKdDWjjyF
14 | itcqWEqdQ3RH6lMEN280UbNWnGFSU1nMpB+yydq2+bIpX0kTvCuyuCqQ1AThDIY5
15 | WFJeGy2cGtUJ6yE4HwnZMrGAJn3LWu5hjkY=
16 | -----END CERTIFICATE REQUEST-----
17 |
--------------------------------------------------------------------------------
/aws/cloudfront-func/README.md:
--------------------------------------------------------------------------------
1 | # Amazon CloudFront Functions
2 | This repository contains example CloudFront functions and instructions to deploy them to CloudFront with Golang
3 |
4 | ## Overview
--------------------------------------------------------------------------------
/aws/cloudfront-func/kvs-hmac-sha256/README.md:
--------------------------------------------------------------------------------
1 | ## Verify Per Request using SHA256 HMAC signature
2 |
3 | **CloudFront Functions event type: viewer request**
4 | tool generate: https://www.freeformatter.com/hmac-generator.html
5 |
--------------------------------------------------------------------------------
/aws/cloudfront-func/kvs-hmac-sha256/test-objects/valid-hmac.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0",
3 | "context": {
4 | "eventType": "viewer-request"
5 | },
6 | "viewer": {
7 | "ip": "0.0.0.0"
8 | },
9 | "request": {
10 | "method": "GET",
11 | "uri": "/index.html",
12 | "headers": {
13 | "signature": {
14 | "value": "af0d733d241fa0a46d803afcb18927756809070428973f409983d0a5f4c0ae63"
15 | },
16 | "requestid": {
17 | "value": "123"
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/aws/codecommit/README.md:
--------------------------------------------------------------------------------
1 | # aws code commit
2 |
3 | ## code repo
4 | ```sh
5 | git config --global credential.helper '!aws codecommit credential-helper $@'
6 |
7 | git config --global credential.UseHttpPath true
8 | ```
9 |
--------------------------------------------------------------------------------
/aws/lambda/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/lambda/.DS_Store
--------------------------------------------------------------------------------
/aws/lambda/README.md:
--------------------------------------------------------------------------------
1 | # lambda
2 |
3 | - requirement:
4 | + node
5 | + npm
6 | + serverless
7 | + aws account
8 |
9 | ## list blog:
10 | - Tạo project bằng serverless framework: https://viblo.asia/p/golang-tao-project-lambda-bang-serverless-EoW4ob9xVml
11 | - Lambda xử lý nhận và return data về cho client: https://viblo.asia/p/go-lambda-apigateway-xu-ly-request-response-5pPLkPY8VRZ
12 | - Lambda CRUD với postgres database: https://viblo.asia/p/go-lambda-crud-voi-postgres-Ny0VGE87JPA
--------------------------------------------------------------------------------
/aws/lambda/courses/sharing/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/courses/sharing/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go
5 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go
6 |
7 | clean:
8 | rm -rf ./bin
9 |
10 | deploy: clean build
11 | sls deploy --verbose
12 |
--------------------------------------------------------------------------------
/aws/lambda/crud/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/crud/Makefile:
--------------------------------------------------------------------------------
1 | # .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/create create/main.go
5 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/update update/main.go
6 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/delete delete/main.go
7 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/read read/main.go
8 | clean:
9 | rm -rf ./bin
10 |
11 | deploy: clean build
12 | sls deploy --verbose
13 |
--------------------------------------------------------------------------------
/aws/lambda/crud/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type UserModel struct {
4 | ID uint `gorm:"primarykey"`
5 | UserName string `gorm:"column:username" bson:"username"`
6 | Email string `gorm:"column:email" bson:"email"`
7 | Phone string `gorm:"column:phone" bson:"phone"`
8 | }
9 |
--------------------------------------------------------------------------------
/aws/lambda/crud/sql.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE "users" (
2 | "id" bigserial,
3 | username character varying(50) COLLATE pg_catalog."default",
4 | name character varying(50) COLLATE pg_catalog."default" NOT NULL,
5 | phone character varying(50) COLLATE pg_catalog."default",
6 | PRIMARY KEY ("id")
7 | );
8 |
--------------------------------------------------------------------------------
/aws/lambda/golang-migration-go1.x-provided.al2/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/golang-migration-go1.x-provided.al2/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean deploy
2 |
3 | build:
4 | # env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/migration/x86 migration/main.go
5 | # env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/bootstrap migration/main.go
6 | env GOARCH=arm64 GOOS=linux go build -ldflags="-s -w" -o bin/bootstrap migration/main.go
7 |
8 | clean:
9 | rm -rf ./bin
10 |
11 | deploy: clean build
12 | sls deploy --verbose
13 |
14 | zip:
15 | zip -j bin/migration/x86.zip bin/x86
16 |
17 | buildv2:
18 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/migration/bootstrap migration/main.go
19 | zip:
20 | zip -j bin/migration.zip bin/migration/bootstrap
21 |
--------------------------------------------------------------------------------
/aws/lambda/golang-migration-go1.x-provided.al2/README.md:
--------------------------------------------------------------------------------
1 | # golang migration runtime go1.x -> provided.al2
2 |
3 | ## runtime go1.x
4 | - make file
5 | ```
6 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o x86 migration/main.go
7 | ```
8 | - serverless
9 | ```
10 | service: golang-migration
11 | frameworkVersion: '3'
12 |
13 | provider:
14 | name: aws
15 | runtime: go1.x
16 | region: ap-southeast-1
17 |
18 | functions:
19 | hello:
20 | handler: x86
21 | events:
22 | - httpApi:
23 | path: /x86
24 | method: get
25 |
26 | ```
27 |
28 | ## runtime provided.al2
29 | - make file
30 | ```
31 | env GOARCH=arm64 GOOS=linux go build -ldflags="-s -w" -o bin/bootstrap migration/main.go
32 | ```
33 | - serverless
34 | ```
35 | service: golang-migration
36 | frameworkVersion: '3'
37 |
38 | provider:
39 | name: aws
40 | runtime: provided.al2 # <- change from go1.x to provided.al2
41 | architecture: arm64 # <- change from x86_64 to arm64
42 | region: ap-southeast-1
43 |
44 | functions:
45 | hello:
46 | # handler: bin/x86 # old
47 | handler: bootstrap # new
48 | events:
49 | - httpApi:
50 | # path: /x86 # old
51 | path: /arm64 # new
52 | method: get
53 | ```
--------------------------------------------------------------------------------
/aws/lambda/golang-migration-go1.x-provided.al2/bootstrap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/lambda/golang-migration-go1.x-provided.al2/bootstrap
--------------------------------------------------------------------------------
/aws/lambda/golang-migration-go1.x-provided.al2/serverless.yml:
--------------------------------------------------------------------------------
1 | service: golang-migration
2 | frameworkVersion: '3'
3 |
4 | provider:
5 | name: aws
6 | runtime: provided.al2 # <- change from go1.x to provided.al2
7 | architecture: arm64 # <- change from x86_64 to arm64
8 | region: ap-southeast-1
9 |
10 | functions:
11 | hello:
12 | # handler: bin/x86 # old
13 | handler: bootstrap # new
14 | events:
15 | - httpApi:
16 | # path: /x86 # old
17 | path: /arm64 # new
18 | method: get
19 |
--------------------------------------------------------------------------------
/aws/lambda/hello-api/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/hello-api/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean zip deploy
2 |
3 | build:
4 | env GOARCH=arm64 GOOS=linux go build -ldflags="-s -w" -o bin/hello/bootstrap hello/main.go
5 | clean:
6 | rm -rf ./bin
7 | deploy: clean build zip
8 | sls deploy --verbose
9 | zip:
10 | zip -j bin/hello.zip bin/hello/bootstrap
11 |
--------------------------------------------------------------------------------
/aws/lambda/hello-api/README.md:
--------------------------------------------------------------------------------
1 | # Golang Hello API
--------------------------------------------------------------------------------
/aws/lambda/hello-api/serverless.yml:
--------------------------------------------------------------------------------
1 | service: golang-hello-api
2 | frameworkVersion: '3'
3 |
4 | provider:
5 | name: aws
6 | runtime: provided.al2
7 | architecture: arm64
8 | region: ap-southeast-1
9 | package:
10 | individually: true
11 | patterns:
12 | - "!./**"
13 | - ./bin/**
14 |
15 | functions:
16 | hello:
17 | handler: bootstrap
18 | package:
19 | artifact: bin/hello.zip
20 | timeout: 6
21 | memorySize: 256
22 | description: function hello api
23 | events:
24 | - httpApi:
25 | path: /hello
26 | method: get
27 |
--------------------------------------------------------------------------------
/aws/lambda/images/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/images/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/insertImage functions/insertImage/main.go
5 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/getImage functions/getImage/main.go
6 |
7 | clean:
8 | rm -rf ./bin
9 |
10 | deploy: clean build
11 | sls deploy --verbose
12 |
--------------------------------------------------------------------------------
/aws/lambda/images/functions/authorizer/authorizer.yml:
--------------------------------------------------------------------------------
1 | authorizerOpenapi:
2 | runtime: python3.8
3 | handler: functions/authorizer/openapi-lambda-auth.lambda_handler
4 | timeout: 3
5 | memorySize: 128
6 | description: authorizer openapi
7 | role: '${file(envs/authorizer/${opt:stage, sls:stage}.json):ROLE}'
8 |
--------------------------------------------------------------------------------
/aws/lambda/images/serverless.yml:
--------------------------------------------------------------------------------
1 |
2 | service: blog-images
3 | frameworkVersion: '3'
4 |
5 | provider:
6 | name: aws
7 | runtime: go1.x
8 | region: ap-southeast-1
9 |
10 | environment:
11 | S3_BUCKET: "s3-south-image-blog"
12 | IMAGE_BLOG: "image-blog/"
13 | # iam:
14 | # role: blog-image-action-s3-from-lambda
15 |
16 | package:
17 | patterns:
18 | - '!./**'
19 | - ./bin/**
20 |
21 | functions:
22 | insertImage:
23 | handler: bin/insertImage
24 | timeout: 3
25 | memorySize: 512
26 | description: insert image of blog to s3
27 | events:
28 | - http:
29 | path: /image/insert
30 | method: post
31 | # private: true
32 | environment:
33 | TEST_ENV: "test"
34 | TEST_1_ENV: "tes11t"
35 | getImage:
36 | handler: bin/getImage
37 | timeout: 3
38 | memorySize: 512
39 | description: get image of blog to s3
40 | events:
41 | - http:
42 | path: /image/get
43 | method: post
44 | # private: true
45 | environment:
46 | TEST_ENV: "test"
47 | TEST_1_ENV: "tes11t"
48 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-1-2/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-1-2/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go
5 | clean:
6 | rm -rf ./bin
7 |
8 | deploy: clean build
9 | sls deploy --verbose
10 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-1-2/README.MD:
--------------------------------------------------------------------------------
1 | # lambda simple:
2 | - create simple lambda function
3 | - read blog: https://viblo.asia/p/golang-aws-lambda-thong-qua-serverless-framework-phan-1-EoW4ob9xVml
4 |
5 |
6 | aws lambda create-event-source-mapping --function-name lambda-go-dev-receive --batch-size 10 --region us-east-1 \
7 | --event-source-arn arn:aws:sqs:us-east-1:064038607558:sqs-demo
8 |
9 |
10 | aws lambda list-event-source-mappings --function-name lambda-go-dev-receive --region us-east-1 \
11 | --event-source-arn arn:aws:sqs:us-east-1:064038607558:sqs-demo
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-1-2/serverless.yml:
--------------------------------------------------------------------------------
1 | service: lambda-go
2 | frameworkVersion: '3'
3 |
4 | provider:
5 | name: aws
6 | runtime: go1.x
7 | timeout: 6
8 | memorySize: 256
9 |
10 | environment:
11 | env_test: "value-test"
12 |
13 | package:
14 | patterns:
15 | - '!./**'
16 | - ./bin/**
17 |
18 | functions:
19 | hello:
20 | handler: bin/hello
21 | events:
22 | - httpApi:
23 | path: /hello
24 | method: post
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/Makefile:
--------------------------------------------------------------------------------
1 | # .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/create create/main.go
5 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/update update/main.go
6 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/delete delete/main.go
7 | env GOARCH=amd64 CGO_ENABLED="0" GOOS=linux go build -ldflags="-s -w" -o bin/read read/main.go
8 | clean:
9 | rm -rf ./bin
10 |
11 | deploy: clean build
12 | sls deploy --verbose
13 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/README.MD:
--------------------------------------------------------------------------------
1 | # lambda simple:
2 | - create simple lambda function
3 | - read blog: https://viblo.asia/p/golang-aws-lambda-thong-qua-serverless-framework-phan-1-EoW4ob9xVml
4 | - handle request and response in api: https://viblo.asia/p/golang-aws-lambda-thong-qua-serverless-framework-phan-2-5pPLkPY8VRZ
5 |
6 | ## Handle API CRUD
7 | - Create table user với script:
8 | ```
9 | CREATE TABLE "users" (
10 | "id" bigserial,
11 | user_name character varying(50) COLLATE pg_catalog."default",
12 | name character varying(50) COLLATE pg_catalog."default" NOT NULL,
13 | phone character varying(50) COLLATE pg_catalog."default",
14 | PRIMARY KEY ("id")
15 | );
16 | ```
17 |
18 | - Add new user:
19 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type UserModel struct {
4 | ID uint `gorm:"primarykey"`
5 | UserName string `gorm:"column:user_name" bson:"user_name"`
6 | Name string `gorm:"column:name" bson:"name"`
7 | Phone string `gorm:"column:phone" bson:"phone"`
8 | }
9 |
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/serverless.yml:
--------------------------------------------------------------------------------
1 | service: lambda-go
2 | frameworkVersion: '3'
3 |
4 | provider:
5 | name: aws
6 | runtime: go1.x
7 | timeout: 6
8 | memorySize: 256
9 | region: ap-southeast-1
10 |
11 | environment:
12 | DB_USER: ""
13 | DB_PASS: ""
14 | DB_HOST: ""
15 | DB_SERVICE: ""
16 |
17 | package:
18 | patterns:
19 | - '!./**'
20 | - ./bin/**
21 |
22 | functions:
23 | create:
24 | handler: bin/create
25 | events:
26 | - httpApi:
27 | path: /create
28 | method: post
29 | delete:
30 | handler: bin/delete
31 | events:
32 | - httpApi:
33 | path: /delete
34 | method: post
35 | read:
36 | handler: bin/read
37 | events:
38 | - httpApi:
39 | path: /read
40 | method: get
41 | update:
42 | handler: bin/update
43 | events:
44 | - httpApi:
45 | path: /update
46 | method: post
--------------------------------------------------------------------------------
/aws/lambda/lambda-go-3/sql.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE "users" (
2 | "id" bigserial,
3 | user_name character varying(50) COLLATE pg_catalog."default",
4 | name character varying(50) COLLATE pg_catalog."default" NOT NULL,
5 | phone character varying(50) COLLATE pg_catalog."default",
6 | PRIMARY KEY ("id")
7 | );
8 |
--------------------------------------------------------------------------------
/aws/s3/delete.go:
--------------------------------------------------------------------------------
1 | package s3
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/aws/aws-sdk-go/aws"
7 | "github.com/aws/aws-sdk-go/aws/session"
8 | "github.com/aws/aws-sdk-go/service/s3"
9 | )
10 |
11 | func (*AwsS3) DeleteFile(key string) error {
12 | session := session.Must(session.NewSession())
13 | svc := s3.New(session)
14 | filename := configS3.PathPrefix + "/" + key
15 | bucket := configS3.Bucket
16 |
17 | _, err := svc.DeleteObject(&s3.DeleteObjectInput{
18 | Bucket: aws.String(bucket),
19 | Key: aws.String(filename),
20 | })
21 | if err != nil {
22 | return errors.New("function svc.DeleteObject() failed, err:" + err.Error())
23 | }
24 |
25 | _ = svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
26 | Bucket: aws.String(bucket),
27 | Key: aws.String(filename),
28 | })
29 | return nil
30 | }
31 |
--------------------------------------------------------------------------------
/aws/s3/error.html:
--------------------------------------------------------------------------------
1 |
this page error
--------------------------------------------------------------------------------
/aws/s3/image/handler-upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/s3/image/handler-upload.png
--------------------------------------------------------------------------------
/aws/s3/image/upload-success-s3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/s3/image/upload-success-s3.png
--------------------------------------------------------------------------------
/aws/s3/image/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/aws/s3/image/upload.png
--------------------------------------------------------------------------------
/aws/s3/index.html:
--------------------------------------------------------------------------------
1 | this home page
--------------------------------------------------------------------------------
/aws/s3/s3.go:
--------------------------------------------------------------------------------
1 | package s3
2 |
3 | type AwsS3 struct{}
4 | type AwsS3Config struct {
5 | Bucket string
6 | Region string
7 | Endpoint string
8 | SecretID string
9 | SecretKey string
10 | BaseURL string
11 | PathPrefix string
12 | S3ForcePathStyle bool
13 | DisableSSL bool
14 | }
15 |
16 | var configS3 = AwsS3Config{
17 | Bucket: "ducnp5",
18 | Region: "ap-southeast-1",
19 | Endpoint: "endpoint",
20 | SecretID: "xxx",
21 | SecretKey: "xxx",
22 | BaseURL: "opendev",
23 | PathPrefix: "",
24 | S3ForcePathStyle: true,
25 | DisableSSL: true,
26 | }
27 |
--------------------------------------------------------------------------------
/aws/s3/upload.go:
--------------------------------------------------------------------------------
1 | package s3
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "mime/multipart"
7 | "time"
8 |
9 | "github.com/aws/aws-sdk-go/aws"
10 | "github.com/aws/aws-sdk-go/aws/session"
11 | "github.com/aws/aws-sdk-go/service/s3/s3manager"
12 | )
13 |
14 | func (*AwsS3) UploadFile(file *multipart.FileHeader) (string, string, error) {
15 | session := session.Must(session.NewSession())
16 |
17 | uploader := s3manager.NewUploader(session)
18 |
19 | fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename)
20 | filename := configS3.PathPrefix + "/" + fileKey
21 | f, openError := file.Open()
22 | if openError != nil {
23 | return "", "", errors.New("function file.Open() failed, err:" + openError.Error())
24 | }
25 | defer f.Close()
26 |
27 | _, err := uploader.Upload(&s3manager.UploadInput{
28 | Bucket: aws.String(configS3.Bucket),
29 | Key: aws.String(filename),
30 | Body: f,
31 | })
32 | if err != nil {
33 | return "", "", err
34 | }
35 |
36 | return configS3.BaseURL + "/" + filename, fileKey, nil
37 | }
38 |
--------------------------------------------------------------------------------
/aws/secretsmanager/README.md:
--------------------------------------------------------------------------------
1 |
2 | # aws secrets manager
3 |
4 | aws secretsmanager list-secrets
5 |
6 | aws secretsmanager list-secrets \
7 | --query "SecretList[?Tags[?Key=='aws secretsmanager list-secrets --filter Key="asm-apse1-cicdhdbank/dev/nhdt/fakeapp/PvoilSecret"']]"
8 |
9 | aws secretsmanager list-secrets --filter Key="asm-apse1-cicdhdbank/dev/nhdt/fakeapp/PvoilSecret"
10 |
11 | aws secretsmanager create-secret --name asm-apse1-cicdhdbank/dev/nhdt/fakeapp/DatabasePassword \
12 | --description "My test secret created with the CLI." \
13 | --secret-string "{\"user\":\"diegor\",\"password\":\"EXAMPLE-PASSWORD\"}"
14 |
15 |
16 |
17 | aws secretsmanager create-secret --name asm-apse1-cicdhdbank/dev/nhdt/fakeapp/PvoilSecret \
18 | --description "My test secret created with the CLI." \
19 | --secret-string "{\"user\":\"diegor\",\"password\":\"EXAMPLE-PASSWORD\"}"
20 |
21 | aws secretsmanager list-secrets | jq '.SecretList[] | select(.Name | contains("fakeapp"))'
22 |
--------------------------------------------------------------------------------
/aws/sqs/README.md:
--------------------------------------------------------------------------------
1 | # simple queue service
2 |
3 | ## prerequisites
4 | - install aws-go sdk
5 | ```go
6 | go get -u github.com/aws/aws-sdk-go/
7 | ```
8 | - aws credentials:
9 |
10 | ## how to create a new sqs queue?
11 |
--------------------------------------------------------------------------------
/aws/sqs/lambda/.gitignore:
--------------------------------------------------------------------------------
1 | # Serverless directories
2 | .serverless
3 |
4 | # golang output binary directory
5 | bin
6 |
7 | # Binaries for programs and plugins
8 | *.exe
9 | *.exe~
10 | *.dll
11 | *.so
12 | *.dylib
13 |
14 | # Test binary, build with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
--------------------------------------------------------------------------------
/aws/sqs/lambda/Makefile:
--------------------------------------------------------------------------------
1 | # .PHONY: build clean deploy
2 |
3 | build:
4 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/push push/main.go
5 | env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/receive receive/main.go
6 | clean:
7 | rm -rf ./bin
8 |
9 | deploy: clean build
10 | sls deploy --verbose
11 |
--------------------------------------------------------------------------------
/aws/sqs/lambda/README.MD:
--------------------------------------------------------------------------------
1 | # lambda simple:
2 | - create simple lambda function
3 | - read blog: https://viblo.asia/p/golang-aws-lambda-thong-qua-serverless-framework-phan-1-EoW4ob9xVml
4 |
5 |
6 | aws lambda create-event-source-mapping --function-name lambda-go-dev-receive --batch-size 10 --region us-east-1 \
7 | --event-source-arn arn:aws:sqs:us-east-1:064038607558:sqs-demo
8 |
9 |
10 | aws lambda list-event-source-mappings --function-name lambda-go-dev-receive --region us-east-1 \
11 | --event-source-arn arn:aws:sqs:us-east-1:064038607558:sqs-demo
--------------------------------------------------------------------------------
/aws/sqs/lambda/serverless.yml:
--------------------------------------------------------------------------------
1 | service: lambda-sqs
2 | frameworkVersion: '3'
3 |
4 | provider:
5 | name: aws
6 | runtime: go1.x
7 | timeout: 6
8 | memorySize: 256
9 |
10 | environment:
11 | env_test: "value-test"
12 |
13 | package:
14 | patterns:
15 | - '!./**'
16 | - ./bin/**
17 |
18 | functions:
19 | push:
20 | handler: bin/push
21 | events:
22 | - httpApi:
23 | path: /push
24 | method: post
25 | receive:
26 | handler: bin/receive
27 | # events:
28 | # - httpApi:
29 | # path: /push
30 | # method: post
--------------------------------------------------------------------------------
/aws/sqs/main.go:
--------------------------------------------------------------------------------
1 | package sqs
2 |
--------------------------------------------------------------------------------
/concurrency/fanInfanOut.go:
--------------------------------------------------------------------------------
1 | package concurrency
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "time"
7 | )
8 |
9 | func MainFanInFanOut() {
10 |
11 | }
12 |
13 | func faninfanout() {
14 | rand := func() interface{} { return rand.Intn(50000000) }
15 | done := make(chan interface{})
16 | defer close(done)
17 | start := time.Now()
18 | randIntStream := toInt(done, repeatFn(done, rand))
19 | fmt.Println("Primes:")
20 | for prime := range take(done, primeFinder(done, randIntStream), 10) {
21 | fmt.Printf("\t%d\n", prime)
22 | }
23 | fmt.Printf("Search took: %v", time.Since(start))
24 | }
25 |
26 | func repeatFn(done <-chan interface{}, fn func() interface{}) <-chan interface{} {
27 | valueStream := make(chan interface{})
28 | go func() {
29 | defer close(valueStream)
30 | for {
31 | select {
32 | case <-done:
33 | return
34 | case valueStream <- fn():
35 | }
36 | }
37 | }()
38 | return valueStream
39 | }
40 |
--------------------------------------------------------------------------------
/concurrency/leak.go:
--------------------------------------------------------------------------------
1 | package concurrency
2 |
3 | import "fmt"
4 |
5 | // MainLeaks goroutine leaks memory
6 | func MainLeaks() {
7 | Leak()
8 | Leak()
9 | }
10 |
11 | func Leak() {
12 | doWork := func(strings <-chan string) <-chan interface{} {
13 | completed := make(chan interface{})
14 | go func() {
15 | defer func() {
16 | fmt.Println("doWork exited.")
17 | }()
18 | defer func() {
19 | close(completed)
20 | }()
21 | for s := range strings {
22 | // Do something interesting
23 | fmt.Println(s)
24 | }
25 | }()
26 | fmt.Println("end function doWork")
27 | return completed
28 | }
29 | fmt.Println("dowork")
30 | doWork(nil)
31 | // Perhaps more work is done here
32 | fmt.Println("Done.")
33 | }
34 |
--------------------------------------------------------------------------------
/concurrency/patterns/fanInfanOut/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | const (
9 | numProducers = 2
10 | numConsumers = 2
11 | )
12 |
13 | func producer(id int, ch chan<- int, wg *sync.WaitGroup) {
14 | defer wg.Done()
15 | for i := 1; i <= 5; i++ {
16 | ch <- i
17 | fmt.Printf("Fanout Producer %d produced %d\n", id, i)
18 | }
19 | }
20 |
21 | func consumer(id int, in <-chan int, out chan<- int, wg *sync.WaitGroup) {
22 | defer wg.Done()
23 | for v := range in {
24 | out <- v * 2
25 | fmt.Printf("FanIn Consumer %d processed %d\n", id, v)
26 | }
27 | }
28 |
29 | func main() {
30 |
31 | input := make(chan int, 10)
32 | output := make(chan int, 10)
33 | var wg sync.WaitGroup
34 | for i := 1; i <= numProducers; i++ {
35 | wg.Add(1)
36 | go producer(i, input, &wg)
37 | }
38 | wg.Wait()
39 | close(input)
40 | for i := 1; i <= numConsumers; i++ {
41 | wg.Add(1)
42 | go consumer(i, input, output, &wg)
43 | }
44 | wg.Wait()
45 | close(output)
46 | for result := range output {
47 | fmt.Println("Ketqua:", result)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/concurrency/patterns/pipeline/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func pipelineStep1(nums []int) <-chan int {
6 | out := make(chan int)
7 | go func() {
8 | for _, n := range nums {
9 | fmt.Println("pipelineStep1", n)
10 | out <- n
11 | }
12 | close(out)
13 | }()
14 | return out
15 | }
16 |
17 | func pipelineStep2(in <-chan int) <-chan int {
18 | out := make(chan int)
19 | go func() {
20 | for n := range in {
21 | fmt.Println("pipelineStep2", n)
22 | out <- n * 2
23 | }
24 | close(out)
25 | }()
26 | return out
27 | }
28 |
29 | func pipelineStep3(in <-chan int) <-chan int {
30 | out := make(chan int)
31 | go func() {
32 | for n := range in {
33 | fmt.Println("pipelineStep3", n)
34 | out <- n + 1
35 | }
36 | close(out)
37 | }()
38 | return out
39 | }
40 |
41 | func main() {
42 | nums := []int{1, 2, 3, 4, 5}
43 | c1 := pipelineStep1(nums)
44 | c2 := pipelineStep2(c1)
45 | c3 := pipelineStep3(c2)
46 | for result := range c3 {
47 | fmt.Println(result)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/concurrency/patterns/rateLimit/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | rate := time.Millisecond * 500
10 | ticker := time.NewTicker(rate)
11 | defer ticker.Stop()
12 |
13 | requests := make(chan int, 10)
14 | for i := 1; i <= 10; i++ {
15 | requests <- i
16 | }
17 | close(requests)
18 |
19 | for req := range requests {
20 | <-ticker.C // Esperar el siguiente tick
21 | fmt.Println("Processing event:", req)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/concurrency/patterns/selectTimeout/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | c := make(chan string)
10 |
11 | go func() {
12 | time.Sleep(2 * time.Second)
13 | c <- "result"
14 | }()
15 |
16 | select {
17 | case res := <-c:
18 | fmt.Println("Received:", res)
19 | case <-time.After(1 * time.Second):
20 | fmt.Println("Timeout")
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/concurrency/patterns/semaphore/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 | func worker(id int, sem chan struct{}, wg *sync.WaitGroup) {
10 | defer wg.Done()
11 | sem <- struct{}{} //
12 | fmt.Printf("Worker %d starting\n", id)
13 | time.Sleep(time.Second)
14 | fmt.Printf("Worker %d done\n", id)
15 | <-sem //
16 | }
17 |
18 | func main() {
19 | const numWorkers = 5
20 | const maxConcurrent = 2
21 | sem := make(chan struct{}, maxConcurrent)
22 | var wg sync.WaitGroup
23 |
24 | for i := 1; i <= numWorkers; i++ {
25 | wg.Add(1)
26 | go worker(i, sem, &wg)
27 | }
28 |
29 | wg.Wait()
30 | }
31 |
--------------------------------------------------------------------------------
/concurrency/patterns/workerpool/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 | const (
10 | numberJobConst = 4
11 | numWorkersConst = 2
12 | )
13 |
14 | func doWorker(id int, jobs <-chan int, kqs chan<- int, wg *sync.WaitGroup) {
15 | for job := range jobs {
16 | fmt.Printf("Do Worker %d started job %d\n", id, job)
17 | time.Sleep(time.Second)
18 | fmt.Printf("Do Worker %d finished job %d\n", id, job)
19 | kqs <- job * 2
20 | }
21 | wg.Done()
22 | }
23 |
24 | func main() {
25 | jobs := make(chan int, numberJobConst)
26 | kqs := make(chan int, numberJobConst)
27 | var wg sync.WaitGroup
28 |
29 | for i := 1; i <= numWorkersConst; i++ {
30 | wg.Add(1)
31 | go doWorker(i, jobs, kqs, &wg)
32 | }
33 |
34 | for j := 1; j <= numberJobConst; j++ {
35 | jobs <- j
36 | }
37 | close(jobs)
38 |
39 | wg.Wait()
40 | close(kqs)
41 |
42 | for kq := range kqs {
43 | fmt.Println("Worker Result:", kq)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/concurrency/singleflight/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "time"
7 |
8 | "golang.org/x/sync/singleflight"
9 | )
10 |
11 | func init() {
12 | rand.Seed(time.Now().UnixNano())
13 | }
14 |
15 | var (
16 | concurrencyControl = &singleflight.Group{}
17 | n = 10
18 | )
19 |
20 | func locking(_ int) (int64, error) {
21 | now := time.Now()
22 | randomNumber := rand.Intn(1000) + 1
23 | time.Sleep(time.Millisecond * time.Duration(randomNumber))
24 | return time.Since(now).Milliseconds(), nil
25 | }
26 | func main() {
27 | now := time.Now()
28 | keyS := "flight"
29 | for i := 1; i <= n; i++ {
30 | go func() {
31 | value, err, s := concurrencyControl.Do(keyS, func() (interface{}, error) {
32 | return locking(i)
33 | })
34 | if err != nil {
35 | fmt.Printf("Goroutine %d: error: %v\n", i, err)
36 | return
37 | }
38 | fmt.Printf("Goroutine %d: result: %v (shared: %v)\n", i, value, s)
39 |
40 | }()
41 | }
42 | time.Sleep(time.Second * 5)
43 | fmt.Println("Done", time.Since(now).Milliseconds())
44 | }
45 |
--------------------------------------------------------------------------------
/concurrency/singleflight/output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/concurrency/singleflight/output.png
--------------------------------------------------------------------------------
/concurrency/syncCond.go:
--------------------------------------------------------------------------------
1 | package concurrency
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 | func CondExample1() {
10 | c := sync.NewCond(&sync.Mutex{})
11 | queue := make([]int, 0, 10)
12 | removeFromQueue := func(delay time.Duration, i int) {
13 | time.Sleep(delay)
14 | c.L.Lock()
15 | fmt.Println("before remove:", queue)
16 | queue = queue[1:]
17 | fmt.Println("after remove:", queue)
18 | c.L.Unlock()
19 | c.Signal()
20 | }
21 | for i := 0; i < 10; i++ {
22 | fmt.Println("start loop;", i)
23 | c.L.Lock()
24 | for len(queue) == 2 {
25 | time.Sleep(time.Second * 2)
26 | fmt.Println("len equal 2, waiting", i)
27 | c.Wait()
28 | }
29 | fmt.Println("Adding to queue", i)
30 | queue = append(queue, i)
31 | go removeFromQueue(1*time.Second, i)
32 | c.L.Unlock()
33 | fmt.Println()
34 | fmt.Println()
35 | }
36 | fmt.Println("after processing, len queue:", len(queue), queue)
37 | }
38 |
--------------------------------------------------------------------------------
/database/index/note.txt:
--------------------------------------------------------------------------------
1 | SHOW max_connections;
2 |
3 | SELECT current_setting('max_connections');
4 |
5 | EXPLAIN ANALYZE
6 | select * from info where uuid = '05aee2f5-aa10-4a15-9e2c-44166380e3a4'
7 | and ref_id =3;
8 |
9 | select count(*) from info ;
10 |
11 | CREATE INDEX idx_info_ref_id_hash ON info USING HASH(ref_id);
12 |
13 |
14 |
15 | CREATE INDEX idx_info_ref_id ON info (ref_id);
16 |
17 | -- delete from info;
18 | SELECT md5(random()::text);
19 |
20 | SELECT uuid_in(overlay(overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring);
21 |
22 | DO $FN$
23 | BEGIN
24 | FOR counter IN 10001..12000 LOOP
25 | insert into info(id, email, location, name,uuid, age,ref_id) values(
26 | counter,
27 | md5(random()::text),
28 | md5(random()::text),
29 | md5(random()::text),
30 | uuid_in(overlay(overlay(md5(random()::text || ':' || random()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring),
31 | counter,
32 | 1
33 | );
34 | END LOOP;
35 | END;
36 | $FN$
37 |
--------------------------------------------------------------------------------
/dtm/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/dtm/.gitignore
--------------------------------------------------------------------------------
/dtm/dtm-cases/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 DTM Development and Communities
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/README-cn.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README.md)
2 |
3 | # dtm 的典型案例
4 |
5 | ## 订单应用
6 | dtm 可以大幅简化非单体的订单系统,详情参见 [order](./order/README-cn.md)
7 |
8 | ## 秒杀应用
9 | dtm 可以应用于精准扣库存的秒杀系统,详情参见[flash](./flash/README-cn.md)
10 |
11 | ## 缓存应用
12 | dtm 可以应用缓存一致性,详情参加[cache](./cache/README-cn.md)
--------------------------------------------------------------------------------
/dtm/dtm-cases/README.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](./README-cn.md)
2 |
3 | # Application of dtm
4 |
5 | ## Order Applications
6 | dtm can significantly simplify the order system for non-monolithic order system, see [order](./order)
7 |
8 | ## Flash-sale Applications
9 | dtm can be used for precise stock deduction of flash-sale, see [flash](./flash)
10 |
11 | ## Caching applications
12 | dtm can be applied to ensure cache consistency, see [cache](./cache)
--------------------------------------------------------------------------------
/dtm/dtm-cases/cache/demo/api-shared.go:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import (
4 | "github.com/dtm-labs/dtm-cases/utils"
5 | "github.com/dtm-labs/dtmcli"
6 | "github.com/dtm-labs/dtmcli/logger"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | func init() {
11 |
12 | BusiApp.POST(BusiAPI+"/deleteKey", utils.WrapHandler(func(c *gin.Context) interface{} {
13 | body := MustMapBodyFrom(c)
14 | key := body["key"].(string)
15 | logger.Infof("deleting key: %s", key)
16 | _, err := rdb.Del(rdb.Context(), key).Result()
17 | return err
18 | }))
19 | BusiApp.GET(BusiAPI+"/queryPrepared", utils.WrapHandler(func(c *gin.Context) interface{} {
20 | bb, err := dtmcli.BarrierFromQuery(c.Request.URL.Query())
21 | if err == nil {
22 | err = bb.QueryPrepared(db)
23 | }
24 | return err
25 | }))
26 | BusiApp.POST(BusiAPI+"/deleteCache", utils.WrapHandler(func(c *gin.Context) interface{} {
27 | body := MustMapBodyFrom(c)
28 | mode := body["mode"].(string)
29 | if mode == "delete" {
30 | return rdb.Del(rdb.Context(), body["key"].(string))
31 | } else {
32 | return dc.TagAsDeleted(body["key"].(string))
33 | }
34 | }))
35 | }
36 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/cache/demo/main.go:
--------------------------------------------------------------------------------
1 | package demo
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "time"
7 |
8 | "github.com/dtm-labs/dtmcli/logger"
9 | "github.com/dtm-labs/rockscache"
10 | "github.com/gin-gonic/gin"
11 | _ "github.com/go-sql-driver/mysql"
12 | )
13 |
14 | var DtmServer = "http://localhost:36789/api/dtmsvr"
15 |
16 | const BusiAPI = "/api/busi"
17 | const BusiPort = 8081
18 |
19 | var BusiUrl = fmt.Sprintf("http://localhost:%d%s", BusiPort, BusiAPI)
20 |
21 | var BusiApp = gin.Default()
22 |
23 | func Main() {
24 | gin.SetMode(gin.ReleaseMode)
25 | rockscache.SetVerbose(true)
26 | logger.InitLog("debug")
27 | startSvr()
28 | time.Sleep(200 * time.Millisecond)
29 | select {}
30 | }
31 |
32 | func startSvr() {
33 | log.Printf("cache examples listening at %d", BusiPort)
34 | go BusiApp.Run(fmt.Sprintf(":%d", BusiPort))
35 | time.Sleep(100 * time.Millisecond)
36 | }
37 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/cache/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/dtm-labs/dtm-cases/cache/demo"
4 |
5 | func main() {
6 | demo.Main()
7 | }
8 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/cache/table.sql:
--------------------------------------------------------------------------------
1 | drop database IF EXISTS cache1;
2 | create database cache1;
3 | use cache1;
4 | drop table IF EXISTS ver;
5 |
6 | create table ver (
7 | k VARCHAR(100) PRIMARY KEY,
8 | v VARCHAR(100) default '',
9 | time_cost varchar(45) default 0
10 | );
--------------------------------------------------------------------------------
/dtm/dtm-cases/flash/README-cn.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README.md)
2 |
3 | # 秒杀应用
4 | 此项目可以结合dtm文档中的 [秒杀应用](https://dtm.pub/app/flash.html)阅读
5 |
6 | ## 概述
7 | 本项目主要演示了dtm如何应用于秒杀系统,将演示秒杀系统中及时发生进程crash,也能够保证精准的扣减库存并创建精准数量的订单。
8 |
9 | #### 启动dtm
10 | [快速启动dtm](https://dtm.pub/guide/install.html)
11 |
12 | #### 运行本例子
13 | `go run main.go`
14 |
15 | #### 发起订单请求
16 | - 发起一个正常完成的秒杀请求 `curl http://localhost:8081/api/busi/flashSales`
17 | - 发起一个完成库存扣减就crash的秒杀请求 `curl http://localhost:8081/api/busi/flashSales-crash` 大约等待十多秒之后,订单创建完成,不受影响
18 |
19 | #### 模拟秒杀活动
20 | `curl http://localhost:8081/api/busi/flashSales-batch`
21 |
22 | 用户发起这个模拟秒杀活动的请求之后,本例子会做如下事情:
23 | 1. 重置各项变量:将库存设置为4,将已创建的订单数重置为0
24 | 2. 发起一个扣减完库存就宕机的请求,然后睡眠0.5s,保证进行下一步前,库存已扣减到3
25 | 3. 发起10个并发的秒杀请求,然后睡眠0.5s,保证进行下一步前,这10个秒杀请求已处理
26 | 4. 此时输出已经创建的订单数量为3,这三个订单都是步骤3中产生的
27 | 5. 大约等待3~5秒,可以看到创建的订单数量变为4,这是因为步骤2里面的全局事务超时检查,最后成功,创建了第4个订单
28 |
29 | 结论:本示例的方法,可以保证Redis中的库存和数据库中的订单,最终严格一致,无需手动校准数据
30 |
31 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/README-cn.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README.md)
2 |
3 | # 订单应用
4 |
5 | 此项目可以结合dtm文档中的 [订单应用](https://dtm.pub/app/order.html)阅读
6 |
7 | ## 概述
8 | 本项目主要演示了dtm如何应用于非单体的订单系统,保证订单中的多个步骤,能够最终“原子”执行,保证最终一致性。
9 |
10 | #### 启动dtm
11 | [快速启动dtm](https://dtm.pub/guide/install.html)
12 |
13 | #### 运行本例子
14 | `go run main.go`
15 |
16 | #### 发起订单请求
17 | - 发起一个正常订单 `curl http://localhost:8081/api/fireSucceed`
18 | - 发起一个因库存不足的回滚订单 `curl http://localhost:8081/api/fireFailed`
19 | - 发起一个因扣减优惠券失败而回滚的订单 `curl http://localhost:8081/api/fireFailedCoupon`
20 |
21 | 以下几点说明一下:
22 | 1. fireFailed 请求,是因为库存不足而失败,此时全局事务会回滚。回滚时会进行库存的回滚操作,此时库存回滚时发生了一个空补偿,在实际操作中不会进行库存相关的业务操作
23 | 2. fireFailedCoupon 请求,是因为扣减优惠券不成功而失败,回滚时会进行库存的回滚操作,此时库存回滚时发生了一个正常补偿,在实际操作中会进行库存相关的业务操作
24 | 3. 开发人员无需关心是否空补偿,开发者只需要关心如何扣减库存和回滚库存,是否空补偿,以及如何回滚空补偿等,都会有dtm框架进行自动处理。
25 |
26 | #### 目录说明
27 | 本项目有以下内容
28 | - main.go: 主程序文件
29 | - service目录:相关各个服务文件
30 | - conf目录:相关配置
31 | - common目录:多个服务共享的代码
32 | - order.sql: 创建本例子所需的订单系统表
33 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/common/common.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "database/sql"
5 |
6 | "github.com/dtm-labs/dtm-cases/order/conf"
7 | "github.com/dtm-labs/dtmcli/dtmimp"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func DBGet() *sql.DB {
12 | db, err := dtmimp.PooledDB(conf.DBConf)
13 | if err != nil {
14 | panic(err)
15 | }
16 | return db
17 | }
18 |
19 | type Req struct {
20 | UserID int `json:"user_id"`
21 | OrderID string `json:"order_id"`
22 | Amount int `json:"amount"` // money amount
23 | ProductID int `json:"product_id"`
24 | ProductCount int `json:"product_count"` // how many product to order
25 | CouponID int `json:"coupon_id"` // optional
26 | }
27 |
28 | func MustGetReq(c *gin.Context) *Req {
29 | var req Req
30 | err := c.BindJSON(&req)
31 | if err != nil {
32 | panic(err)
33 | }
34 | if req.UserID == 0 {
35 | panic("user_id not specified")
36 | }
37 | if req.OrderID == "" {
38 | panic("order_Id not specified")
39 | }
40 | if req.Amount == 0 {
41 | panic("amount not specified")
42 | }
43 | if req.ProductID == 0 {
44 | panic("product_id not specified")
45 | }
46 | return &req
47 | }
48 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/conf/conf.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/dtm-labs/dtmcli"
7 | )
8 |
9 | var DBConf = dtmcli.DBConf{
10 | Driver: "mysql",
11 | Host: "en.dtm.pub",
12 | User: "dtm",
13 | Password: "passwd123dtm",
14 | Port: 3306,
15 | }
16 |
17 | var DtmServer = "http://localhost:36789/api/dtmsvr"
18 |
19 | const BusiAPI = "/api/busi"
20 | const BusiPort = 8081
21 |
22 | var BusiUrl = fmt.Sprintf("http://localhost:%d%s", BusiPort, BusiAPI)
23 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/service/api.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/dtm-labs/dtm-cases/order/common"
5 | "github.com/dtm-labs/dtm-cases/order/conf"
6 | "github.com/dtm-labs/dtm-cases/utils"
7 | "github.com/dtm-labs/dtmcli"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func AddAPIRoute(app *gin.Engine) {
12 | app.POST("/api/busi/submitOrder", utils.WrapHandler(func(c *gin.Context) interface{} {
13 | req := common.MustGetReq(c)
14 | saga := dtmcli.NewSaga(conf.DtmServer, "gid-"+req.OrderID).
15 | Add(conf.BusiUrl+"/orderCreate", conf.BusiUrl+"/orderCreateRevert", &req).
16 | Add(conf.BusiUrl+"/stockDeduct", conf.BusiUrl+"/stockDeductRevert", &req).
17 | Add(conf.BusiUrl+"/couponUse", conf.BusiUrl+"couponUseRevert", &req).
18 | Add(conf.BusiUrl+"/payCreate", conf.BusiUrl+"/payCreateRevert", &req)
19 | return saga.Submit()
20 | }))
21 | }
22 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/service/order.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "database/sql"
5 |
6 | "github.com/dtm-labs/dtm-cases/order/common"
7 | "github.com/dtm-labs/dtm-cases/utils"
8 | "github.com/dtm-labs/dtmcli/dtmimp"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | func AddOrderRoute(app *gin.Engine) {
13 | app.POST("/api/busi/orderCreate", utils.WrapHandler(func(c *gin.Context) interface{} {
14 | req := common.MustGetReq(c)
15 | bb := utils.MustBarrierFrom(c)
16 | return bb.CallWithDB(common.DBGet(), func(tx *sql.Tx) error {
17 | _, err := dtmimp.DBExec(tx,
18 | "insert into ord.order1(user_id, order_id, product_id, amount, status) values(?,?,?,?,'PAYING')",
19 | req.UserID, req.OrderID, req.ProductID, req.Amount)
20 | return err
21 | })
22 | }))
23 | app.POST("/api/busi/orderCreateRevert", utils.WrapHandler(func(c *gin.Context) interface{} {
24 | req := common.MustGetReq(c)
25 | bb := utils.MustBarrierFrom(c)
26 | return bb.CallWithDB(common.DBGet(), func(tx *sql.Tx) error {
27 | _, err := dtmimp.DBExec(tx,
28 | "update ord.order1 set status='FAILED', update_time=now() where order_id=?",
29 | req.OrderID)
30 | return err
31 | })
32 | }))
33 | }
34 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/service/pay.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "database/sql"
5 |
6 | "github.com/dtm-labs/dtm-cases/order/common"
7 | "github.com/dtm-labs/dtm-cases/utils"
8 | "github.com/dtm-labs/dtmcli/dtmimp"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | func AddPayRoute(app *gin.Engine) {
13 | app.POST("/api/busi/payCreate", utils.WrapHandler(func(c *gin.Context) interface{} {
14 | req := common.MustGetReq(c)
15 | bb := utils.MustBarrierFrom(c)
16 | return bb.CallWithDB(common.DBGet(), func(tx *sql.Tx) error {
17 | _, err := dtmimp.DBExec(tx,
18 | "insert into ord.pay(user_id, order_id, amount, status) values(?,?,?,'CREATED')",
19 | req.UserID, req.OrderID, req.Amount)
20 | return err
21 | })
22 | }))
23 | app.POST("/api/busi/payCreateRevert", utils.WrapHandler(func(c *gin.Context) interface{} {
24 | req := common.MustGetReq(c)
25 | bb := utils.MustBarrierFrom(c)
26 | return bb.CallWithDB(common.DBGet(), func(tx *sql.Tx) error {
27 | _, err := dtmimp.DBExec(tx,
28 | "update ord.pay set status='CANCELED', update_time=now() where order_id=?",
29 | req.OrderID)
30 | return err
31 | })
32 | }))
33 | }
34 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/order/service/types.go:
--------------------------------------------------------------------------------
1 | package service
2 |
--------------------------------------------------------------------------------
/dtm/dtm-cases/utils/utils.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 | "time"
7 |
8 | "github.com/dtm-labs/dtmcli"
9 | "github.com/dtm-labs/dtmcli/logger"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | // WrapHandler used by examples. much more simpler than WrapHandler2
14 | func WrapHandler(fn func(*gin.Context) interface{}) gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | began := time.Now()
17 | ret := fn(c)
18 | status, res := dtmcli.Result2HttpJSON(ret)
19 |
20 | b, _ := json.Marshal(res)
21 | if status == http.StatusOK || status == http.StatusTooEarly {
22 | logger.Infof("%2dms %d %s %s %s", time.Since(began).Milliseconds(), status, c.Request.Method, c.Request.RequestURI, string(b))
23 | } else {
24 | logger.Errorf("%2dms %d %s %s %s", time.Since(began).Milliseconds(), status, c.Request.Method, c.Request.RequestURI, string(b))
25 | }
26 | c.JSON(status, res)
27 | }
28 | }
29 |
30 | func MustBarrierFrom(c *gin.Context) *dtmcli.BranchBarrier {
31 | bb, err := dtmcli.BarrierFromQuery(c.Request.URL.Query())
32 | if err != nil {
33 | panic(err)
34 | }
35 | return bb
36 | }
37 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 | dtm-examples
17 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 DTM Development and Communities
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/busi/base_jrpc.go:
--------------------------------------------------------------------------------
1 | package busi
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/dtm-labs/client/dtmcli/dtmimp"
7 | "github.com/dtm-labs/client/dtmcli/logger"
8 | "github.com/dtm-labs/dtm-examples/dtmutil"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | // BusiJrpcURL url prefix for busi
13 | var BusiJrpcURL = fmt.Sprintf("http://localhost:%d/api/json-rpc?method=", BusiPort)
14 |
15 | func addJrpcRoute(app *gin.Engine) {
16 | app.POST("/api/json-rpc", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
17 | var data map[string]interface{}
18 | err := c.BindJSON(&data)
19 | dtmimp.E2P(err)
20 | logger.Debugf("method is: %s", data["method"])
21 | var rerr map[string]interface{}
22 | r := MainSwitch.JrpcResult.Fetch()
23 | if r != "" {
24 | rerr = map[string]interface{}{
25 | "code": map[string]int{
26 | "FAILURE": dtmimp.JrpcCodeFailure,
27 | "ONGOING": dtmimp.JrpcCodeOngoing,
28 | "OTHER": -23977,
29 | },
30 | }
31 | }
32 | return map[string]interface{}{
33 | "jsonrpc": "2.0",
34 | "error": rerr,
35 | "id": data["id"],
36 | }
37 | }))
38 | }
39 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/busi/startup.go:
--------------------------------------------------------------------------------
1 | package busi
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | grpc "google.golang.org/grpc"
6 | )
7 |
8 | // Startup startup the busi's grpc and http service
9 | func Startup() (*gin.Engine, *grpc.Server) {
10 | svr := GrpcStartup()
11 | app := BaseAppStartup()
12 | return app, svr
13 | }
14 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/dtmutil/consts.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmutil
8 |
9 | const (
10 | // DefaultHTTPServer default url for http server. used by test and examples
11 | DefaultHTTPServer = "http://localhost:36789/api/dtmsvr"
12 | // DefaultJrpcServer default url for http json-rpc server. used by test and examples
13 | DefaultJrpcServer = "http://localhost:36789/api/json-rpc"
14 | // DefaultGrpcServer default url for grpc server. used by test and examples
15 | DefaultGrpcServer = "localhost:36790"
16 | )
17 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/grpc_msg.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli/logger"
11 | dtmgrpc "github.com/dtm-labs/client/dtmgrpc"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/lithammer/shortuuid/v3"
15 | )
16 |
17 | func init() {
18 | AddCommand("grpc_msg", func() string {
19 | req := &busi.ReqGrpc{Amount: 30}
20 | gid := shortuuid.New()
21 | msg := dtmgrpc.NewMsgGrpc(dtmutil.DefaultGrpcServer, gid).
22 | Add(busi.BusiGrpc+"/busi.Busi/TransOut", req).
23 | Add(busi.BusiGrpc+"/busi.Busi/TransIn", req)
24 | err := msg.Submit()
25 | logger.FatalIfError(err)
26 | return msg.Gid
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/grpc_saga_barrier.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli/logger"
11 | "github.com/dtm-labs/client/dtmgrpc"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/lithammer/shortuuid/v3"
15 | )
16 |
17 | func init() {
18 | AddCommand("grpc_saga_barrier", func() string {
19 | req := &busi.ReqGrpc{Amount: 30}
20 | gid := shortuuid.New()
21 | saga := dtmgrpc.NewSagaGrpc(dtmutil.DefaultGrpcServer, gid).
22 | Add(busi.BusiGrpc+"/busi.Busi/TransOutBSaga", busi.BusiGrpc+"/busi.Busi/TransOutRevertBSaga", req).
23 | Add(busi.BusiGrpc+"/busi.Busi/TransInBSaga", busi.BusiGrpc+"/busi.Busi/TransInRevertBSaga", req)
24 | err := saga.Submit()
25 | logger.FatalIfError(err)
26 | return saga.Gid
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/grpc_saga_other.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "github.com/dtm-labs/client/dtmcli/dtmimp"
5 | "github.com/dtm-labs/client/dtmcli/logger"
6 | dtmgrpc "github.com/dtm-labs/client/dtmgrpc"
7 | "github.com/dtm-labs/dtm-examples/busi"
8 | "github.com/dtm-labs/dtm-examples/dtmutil"
9 | "github.com/lithammer/shortuuid/v3"
10 | )
11 |
12 | func init() {
13 | AddCommand("grpc_saga_hybrid", func() string {
14 | req := &busi.ReqGrpc{Amount: 30}
15 | gid := shortuuid.New()
16 | saga := dtmgrpc.NewSagaGrpc(dtmutil.DefaultGrpcServer, gid).
17 | Add(busi.BusiGrpc+"/busi.Busi/TransOut", busi.BusiGrpc+"/busi.Busi/TransOutRevert", req)
18 | saga.Steps = append(saga.Steps, map[string]string{"action": busi.Busi + "/TransIn", "compensate": busi.Busi + "/TransInRevert"})
19 | saga.BinPayloads = append(saga.BinPayloads, dtmimp.MustMarshal(&busi.ReqGrpc{Amount: 30}))
20 |
21 | err := saga.Submit()
22 | logger.FatalIfError(err)
23 | return saga.Gid
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/grpc_xa.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli/logger"
11 | "github.com/dtm-labs/client/dtmgrpc"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/lithammer/shortuuid/v3"
15 | "google.golang.org/protobuf/types/known/emptypb"
16 | )
17 |
18 | func init() {
19 | AddCommand("grpc_xa", func() string {
20 | gid := shortuuid.New()
21 | req := &busi.ReqGrpc{Amount: 30}
22 | err := dtmgrpc.XaGlobalTransaction(dtmutil.DefaultGrpcServer, gid, func(xa *dtmgrpc.XaGrpc) error {
23 | r := &emptypb.Empty{}
24 | err := xa.CallBranch(req, busi.BusiGrpc+"/busi.Busi/TransOutXa", r)
25 | if err != nil {
26 | return err
27 | }
28 | err = xa.CallBranch(req, busi.BusiGrpc+"/busi.Busi/TransInXa", r)
29 | return err
30 | })
31 | logger.FatalIfError(err)
32 | return gid
33 | })
34 | }
35 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_more.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "github.com/dtm-labs/client/dtmcli"
5 | "github.com/dtm-labs/client/dtmcli/logger"
6 | "github.com/dtm-labs/dtm-examples/busi"
7 | "github.com/dtm-labs/dtm-examples/dtmutil"
8 | "github.com/lithammer/shortuuid/v3"
9 | )
10 |
11 | func init() {
12 | AddCommand("http_saga_multiSource", func() string {
13 | req := &busi.ReqHTTP{Amount: 30}
14 | saga := dtmcli.NewSaga(dtmutil.DefaultHTTPServer, shortuuid.New()).
15 | Add(busi.Busi+"/SagaMultiSource", busi.Busi+"/SagaMultiSourceRevert", req)
16 | logger.Debugf("saga busi trans submit")
17 | err := saga.Submit()
18 | logger.Debugf("result gid is: %s", saga.Gid)
19 | logger.FatalIfError(err)
20 | return saga.Gid
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_saga_gorm_barrier.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli"
11 | "github.com/dtm-labs/client/dtmcli/logger"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/lithammer/shortuuid/v3"
15 | )
16 |
17 | func init() {
18 | AddCommand("http_saga_gorm_barrier", func() string {
19 | logger.Debugf("a busi transaction begin")
20 | req := &busi.ReqHTTP{Amount: 30}
21 | saga := dtmcli.NewSaga(dtmutil.DefaultHTTPServer, shortuuid.New()).
22 | Add(busi.Busi+"/SagaBTransOutGorm", busi.Busi+"/SagaBTransOutCom", req).
23 | Add(busi.Busi+"/SagaBTransIn", busi.Busi+"/SagaBTransInCom", req)
24 | logger.Debugf("busi trans submit")
25 | err := saga.Submit()
26 | logger.FatalIfError(err)
27 | return saga.Gid
28 | })
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_tcc_barrier.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli"
11 | "github.com/dtm-labs/client/dtmcli/logger"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/go-resty/resty/v2"
15 | "github.com/lithammer/shortuuid/v3"
16 | )
17 |
18 | func init() {
19 | AddCommand("http_tcc_barrier", func() string {
20 | logger.Debugf("tcc transaction begin")
21 | gid := shortuuid.New()
22 | err := dtmcli.TccGlobalTransaction(dtmutil.DefaultHTTPServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
23 | resp, err := tcc.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TccBTransOutTry",
24 | busi.Busi+"/TccBTransOutConfirm", busi.Busi+"/TccBTransOutCancel")
25 | if err != nil {
26 | return resp, err
27 | }
28 | return tcc.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TccBTransInTry", busi.Busi+"/TccBTransInConfirm", busi.Busi+"/TccBTransInCancel")
29 | })
30 | logger.FatalIfError(err)
31 | return gid
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_workflow_xa.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "database/sql"
5 |
6 | "github.com/dtm-labs/client/dtmcli"
7 | "github.com/dtm-labs/client/dtmcli/dtmimp"
8 | "github.com/dtm-labs/client/dtmcli/logger"
9 | "github.com/dtm-labs/client/workflow"
10 | "github.com/dtm-labs/dtm-examples/busi"
11 | "github.com/lithammer/shortuuid/v3"
12 | )
13 |
14 | func init() {
15 | AddCommand("http_workflow_xa", func() string {
16 | wfName := "wf_xa"
17 | err := workflow.Register(wfName, func(wf *workflow.Workflow, data []byte) error {
18 | _, err := wf.NewBranch().DoXa(busi.BusiConf, func(db *sql.DB) ([]byte, error) {
19 | return nil, busi.SagaAdjustBalance(db, busi.TransOutUID, -30, dtmcli.ResultSuccess)
20 | })
21 | if err != nil {
22 | return err
23 | }
24 | _, err = wf.NewBranch().DoXa(busi.BusiConf, func(db *sql.DB) ([]byte, error) {
25 | return nil, busi.SagaAdjustBalance(db, busi.TransInUID, 30, dtmcli.ResultSuccess)
26 | })
27 | return err
28 | })
29 | logger.FatalIfError(err)
30 |
31 | req := &busi.ReqHTTP{Amount: 30}
32 | gid := shortuuid.New()
33 | err = workflow.Execute(wfName, gid, dtmimp.MustMarshal(req))
34 | logger.Infof("result is: %v", err)
35 | return gid
36 | })
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_xa.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli"
11 | "github.com/dtm-labs/client/dtmcli/logger"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/go-resty/resty/v2"
15 | "github.com/lithammer/shortuuid/v3"
16 | )
17 |
18 | func init() {
19 | AddCommand("http_xa", func() string {
20 | gid := shortuuid.New()
21 | err := dtmcli.XaGlobalTransaction(dtmutil.DefaultHTTPServer, gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
22 | resp, err := xa.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TransOutXa")
23 | if err != nil {
24 | return resp, err
25 | }
26 | return xa.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TransInXa")
27 | })
28 | logger.FatalIfError(err)
29 | return gid
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/http_xa_gorm.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package examples
8 |
9 | import (
10 | "github.com/dtm-labs/client/dtmcli"
11 | "github.com/dtm-labs/client/dtmcli/logger"
12 | "github.com/dtm-labs/dtm-examples/busi"
13 | "github.com/dtm-labs/dtm-examples/dtmutil"
14 | "github.com/go-resty/resty/v2"
15 | "github.com/lithammer/shortuuid/v3"
16 | )
17 |
18 | func init() {
19 | AddCommand("http_xa_gorm", func() string {
20 | gid := shortuuid.New()
21 | err := dtmcli.XaGlobalTransaction(dtmutil.DefaultHTTPServer, gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
22 | resp, err := xa.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TransOutXaGorm")
23 | if err != nil {
24 | return resp, err
25 | }
26 | return xa.CallBranch(&busi.ReqHTTP{Amount: 30}, busi.Busi+"/TransInXa")
27 | })
28 | logger.FatalIfError(err)
29 | return gid
30 | })
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/examples/utils.go:
--------------------------------------------------------------------------------
1 | package examples
2 |
3 | import (
4 | "github.com/dtm-labs/client/dtmcli/dtmimp"
5 | "github.com/dtm-labs/client/dtmgrpc/dtmgimp"
6 | "github.com/dtm-labs/dtm-examples/busi"
7 | )
8 |
9 | func MustUnmarshalReqGrpc(data []byte) *busi.ReqGrpc {
10 | var req busi.ReqGrpc
11 | dtmgimp.MustProtoUnmarshal(data, &req)
12 | return &req
13 | }
14 |
15 | func MustUnmarshalReqHTTP(data []byte) *busi.ReqHTTP {
16 | var req busi.ReqHTTP
17 | dtmimp.MustUnmarshal(data, &req)
18 | return &req
19 | }
20 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/dtm-labs/dtm-examples
2 |
3 | go 1.15
4 |
5 | require (
6 | github.com/dtm-labs/client v1.17.3
7 | github.com/gin-gonic/gin v1.7.7
8 | github.com/go-redis/redis/v8 v8.11.5
9 | github.com/go-resty/resty/v2 v2.7.0
10 | github.com/go-sql-driver/mysql v1.6.0
11 | github.com/lib/pq v1.10.3
12 | github.com/lithammer/shortuuid/v3 v3.0.7
13 | go.mongodb.org/mongo-driver v1.9.1
14 | google.golang.org/grpc v1.48.0
15 | google.golang.org/protobuf v1.28.0
16 | gorm.io/driver/mysql v1.0.3
17 | gorm.io/driver/postgres v1.2.1
18 | gorm.io/gorm v1.22.2
19 | )
20 |
21 | // replace github.com/dtm-labs/client/dtmcli => /Users/wangxi/dtm/dtmcli
22 |
23 | // replace github.com/dtm-labs/client/dtmgrpc => /Users/wangxi/dtm/dtmgrpc
24 |
--------------------------------------------------------------------------------
/dtm/dtm-examples/sync-from-dtm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -x
4 |
5 | rm -rf busi dtmutil
6 | cp -rf ../dtm/test/busi ./
7 | cp -rf ../dtm/dtmutil ./
8 | sed -i '' -e 's/dtm-labs\/dtm\/dtmutil/dtm-labs\/dtm-examples\/dtmutil/g' *.go */**.go
9 | rm -rf dtmutil/*_test.go
10 | sed -i '' -e 's/dtm-labs\/dtm\/client\/dtmcli/dtm-labs\/client\/dtmcli/g' *.go */**.go
11 | sed -i '' -e 's/dtm-labs\/dtm\/client\/dtmgrpc/dtm-labs\/client\/dtmgrpc/g' *.go */**.go
12 | sed -i '' -e 's/dtm-labs\/dtm\/client\/workflow/dtm-labs\/client\/workflow/g' *.go */**.go
13 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmcli/dtmimp/README-cn.md:
--------------------------------------------------------------------------------
1 | ## 注意
2 | 此包带imp后缀,主要被dtm内部使用,相关接口可能会发生变更,请勿使用这里的接口
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmcli/dtmimp/README.md:
--------------------------------------------------------------------------------
1 | ## Notice
2 | Please donot use this package, and this package should only be used in dtm internally. The interfaces are not stable, and package name has postfix "imp"
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmcli/dtmimp/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmimp
8 |
9 | import "database/sql"
10 |
11 | // DB inteface of dtmcli db
12 | type DB interface {
13 | Exec(query string, args ...interface{}) (sql.Result, error)
14 | QueryRow(query string, args ...interface{}) *sql.Row
15 | }
16 |
17 | // DBConf defines db config
18 | type DBConf struct {
19 | Driver string `yaml:"Driver"`
20 | Host string `yaml:"Host"`
21 | Port int64 `yaml:"Port"`
22 | User string `yaml:"User"`
23 | Password string `yaml:"Password"`
24 | Db string `yaml:"Db"`
25 | Schema string `yaml:"Schema"`
26 | }
27 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmcli/logger/logger.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "github.com/dtm-labs/logger"
5 | )
6 |
7 | var (
8 | // WithLogger replaces default logger
9 | WithLogger = logger.WithLogger
10 | // InitLog is an initialization for a logger
11 | // level can be: debug info warn error
12 | InitLog = logger.InitLog
13 | // InitLog2 specify advanced log config
14 | InitLog2 = logger.InitLog2
15 | // Debugf log to level debug
16 | Debugf = logger.Debugf
17 |
18 | // Infof log to level info
19 | Infof = logger.Infof
20 |
21 | // Warnf log to level warn
22 | Warnf = logger.Warnf
23 | // Errorf log to level error
24 | Errorf = logger.Errorf
25 |
26 | // FatalfIf log to level error
27 | FatalfIf = logger.FatalfIf
28 |
29 | // FatalIfError if err is not nil, then log to level fatal and call os.Exit
30 | FatalIfError = logger.FatalIfError
31 | )
32 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmgrpc/barrier.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmgrpc
8 |
9 | import (
10 | "context"
11 |
12 | "github.com/dtm-labs/client/dtmcli"
13 | "github.com/dtm-labs/client/dtmgrpc/dtmgimp"
14 | )
15 |
16 | // BarrierFromGrpc generate a Barrier from grpc context
17 | func BarrierFromGrpc(ctx context.Context) (*dtmcli.BranchBarrier, error) {
18 | tb := dtmgimp.TransBaseFromGrpc(ctx)
19 | return dtmcli.BarrierFrom(tb.TransType, tb.Gid, tb.BranchID, tb.Op)
20 | }
21 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmgrpc/dtmgimp/README-cn.md:
--------------------------------------------------------------------------------
1 | ## 注意
2 | 此包带imp后缀,主要被dtm内部使用,相关接口可能会发生变更,请勿使用这里的接口
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmgrpc/dtmgimp/README.md:
--------------------------------------------------------------------------------
1 | ## Notice
2 | Please donot use this package, and this package should only be used in dtm internally. The interfaces are not stable, and package name has postfix "imp"
--------------------------------------------------------------------------------
/dtm/dtm-lab/dtmgrpc/options.go:
--------------------------------------------------------------------------------
1 | package dtmgrpc
2 |
3 | import (
4 | "github.com/dtm-labs/client/dtmcli/dtmimp"
5 | )
6 |
7 | // TransBaseOption setup func for TransBase
8 | type TransBaseOption func(tb *dtmimp.TransBase)
9 |
10 | // WithBranchHeaders setup TransBase.BranchHeaders
11 | func WithBranchHeaders(headers map[string]string) TransBaseOption {
12 | return func(tb *dtmimp.TransBase) {
13 | tb.BranchHeaders = headers
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/dummy.go:
--------------------------------------------------------------------------------
1 | package client_test
2 |
3 | import (
4 | _ "github.com/dtm-labs/client/dtmcli"
5 | _ "github.com/dtm-labs/client/dtmgrpc"
6 | _ "github.com/dtm-labs/client/workflow"
7 | )
8 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/dtm-labs/client
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/dtm-labs/dtmdriver v0.0.6
7 | github.com/go-redis/redis/v8 v8.11.5
8 | github.com/go-resty/resty/v2 v2.7.0
9 | go.mongodb.org/mongo-driver v1.9.1
10 | google.golang.org/grpc v1.48.0
11 | google.golang.org/protobuf v1.28.0
12 | )
13 |
14 | require (
15 | github.com/dtm-labs/logger v0.0.1
16 | github.com/stretchr/testify v1.8.0 // indirect
17 | )
18 |
19 | retract v1.18.7
20 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/workflow/dummyReadCloser.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | )
7 |
8 | // NewRespBodyFromBytes creates an io.ReadCloser from a byte slice
9 | // that is suitable for use as an http response body.
10 | func NewRespBodyFromBytes(body []byte) io.ReadCloser {
11 | return &dummyReadCloser{body: bytes.NewReader(body)}
12 | }
13 |
14 | type dummyReadCloser struct {
15 | body io.ReadSeeker
16 | }
17 |
18 | func (d *dummyReadCloser) Read(p []byte) (n int, err error) {
19 | return d.body.Read(p)
20 | }
21 |
22 | func (d *dummyReadCloser) Close() error {
23 | _, _ = d.body.Seek(0, io.SeekEnd)
24 | return nil
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/workflow/factory.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/dtm-labs/logger"
8 | )
9 |
10 | type workflowFactory struct {
11 | protocol string
12 | httpDtm string
13 | httpCallback string
14 | grpcDtm string
15 | grpcCallback string
16 | handlers map[string]*wfItem
17 | }
18 |
19 | var defaultFac = workflowFactory{
20 | handlers: map[string]*wfItem{},
21 | }
22 |
23 | func (w *workflowFactory) execute(ctx context.Context, name string, gid string, data []byte) ([]byte, error) {
24 | handler := w.handlers[name]
25 | if handler == nil {
26 | return nil, fmt.Errorf("workflow '%s' not registered. please register at startup", name)
27 | }
28 | wf := w.newWorkflow(ctx, name, gid, data)
29 | for _, fn := range handler.custom {
30 | fn(wf)
31 | }
32 | return wf.process(handler.fn, data)
33 | }
34 |
35 | func (w *workflowFactory) register(name string, handler WfFunc2, custom ...func(wf *Workflow)) error {
36 | e := w.handlers[name]
37 | if e != nil {
38 | return fmt.Errorf("a handler already exists for %s", name)
39 | }
40 | logger.Debugf("workflow '%s' registered.", name)
41 | w.handlers[name] = &wfItem{
42 | fn: handler,
43 | custom: custom,
44 | }
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/workflow/server.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/dtm-labs/client/dtmcli/dtmimp"
7 | "github.com/dtm-labs/client/dtmgrpc"
8 | "github.com/dtm-labs/client/dtmgrpc/dtmgimp"
9 | "github.com/dtm-labs/client/workflow/wfpb"
10 | "google.golang.org/grpc/codes"
11 | "google.golang.org/grpc/status"
12 | "google.golang.org/protobuf/types/known/emptypb"
13 | )
14 |
15 | type workflowServer struct {
16 | wfpb.UnimplementedWorkflowServer
17 | }
18 |
19 | func (s *workflowServer) Execute(ctx context.Context, wd *wfpb.WorkflowData) (*emptypb.Empty, error) {
20 | if defaultFac.protocol != dtmimp.ProtocolGRPC {
21 | return nil, status.Errorf(codes.Internal, "workflow server not inited. please call workflow.InitGrpc first")
22 | }
23 | tb := dtmgimp.TransBaseFromGrpc(ctx)
24 | _, err := defaultFac.execute(ctx, tb.Op, tb.Gid, wd.Data)
25 | return &emptypb.Empty{}, dtmgrpc.DtmError2GrpcError(err)
26 | }
27 |
--------------------------------------------------------------------------------
/dtm/dtm-lab/workflow/wfpb/wf.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "./wfpb";
4 | import "google/protobuf/empty.proto";
5 |
6 | package workflow;
7 |
8 | // The Workflow service definition.
9 | service Workflow {
10 | rpc Execute(WorkflowData) returns (google.protobuf.Empty) {}
11 | }
12 |
13 | message WorkflowData {
14 | bytes Data = 1;
15 | }
16 |
--------------------------------------------------------------------------------
/dtm/dtm/.gitignore:
--------------------------------------------------------------------------------
1 | conf.yml
2 | *.out
3 | *.log
4 | # dist
5 | .idea/**
6 | .vscode
7 | default.etcd
8 | */**/*.bolt
9 | bench/bench
10 | helper/bench/bench
11 | helper/qs/qs
12 | # Output file of unit test coverage
13 | coverage.*
14 | profile.*
15 | test.sh
16 | dtm
17 | dtm-*
18 | dtm.*
19 | cache
20 |
21 |
--------------------------------------------------------------------------------
/dtm/dtm/Makefile:
--------------------------------------------------------------------------------
1 | # dev env https://www.dtm.pub/other/develop.html
2 | all: fmt lint test_redis
3 | .PHONY: all
4 |
5 | fmt:
6 | @gofmt -s -w ./
7 |
8 | lint:
9 | revive -config revive.toml ./...
10 |
11 | .PHONY: test
12 | test:
13 | @go test ./...
14 |
15 | test_redis:
16 | TEST_STORE=redis go test ./...
17 |
18 | test_all:
19 | TEST_STORE=redis go test ./...
20 | TEST_STORE=boltdb go test ./...
21 | TEST_STORE=mysql go test ./...
22 | TEST_STORE=postgres go test ./...
23 |
24 | cover_test:
25 | ./helper/test-cover.sh
26 |
27 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/.env:
--------------------------------------------------------------------------------
1 | VITE_ADMIN_VERSION="v0.0.0-dev"
2 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/README.md:
--------------------------------------------------------------------------------
1 | # DTM-Admin
2 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Dtm
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {}
5 | }
6 | }
--------------------------------------------------------------------------------
/dtm/dtm/admin/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/dtm/dtm/admin/public/favicon.ico
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/assets/css/index.css:
--------------------------------------------------------------------------------
1 | /* @tailwind base; */
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/icons/readme.md:
--------------------------------------------------------------------------------
1 | # ICon Component
2 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/icons/svg/fullscreen.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import router from '/@/router/index'
4 | import { pinia } from '/@/store'
5 | import { useLayoutStore } from '/@/store/modules/layout'
6 | import '/@/permission'
7 |
8 | import 'ant-design-vue/dist/antd.css'
9 | import '/@/assets/css/index.css'
10 | import 'virtual:svg-icons-register'
11 |
12 | const app = createApp(App)
13 | app.use(router)
14 | app.use(pinia)
15 | app.mount('#app')
16 |
17 | window.onunhandledrejection = (ev: PromiseRejectionEvent) => {
18 | showAlert(ev.reason.stack || ev.reason.message)
19 | }
20 | window.onerror = err => {
21 | if (typeof err === 'string') {
22 | return showAlert(err)
23 | }
24 | showAlert(JSON.stringify(err))
25 | }
26 |
27 | function showAlert(msg: string) {
28 | const layout = useLayoutStore()
29 | if (!layout.globalError) {
30 | layout.setGlobalError(msg)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/permission.ts:
--------------------------------------------------------------------------------
1 | import router from '/@/router'
2 | import { configure, start, done } from 'nprogress'
3 | import { useLayoutStore } from './store/modules/layout'
4 |
5 | configure({ showSpinner: false })
6 |
7 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
8 | const defaultRoutePath = '/'
9 |
10 | router.beforeEach((to) => {
11 | start()
12 |
13 | const { getMenubar, concatAllowRoutes } = useLayoutStore()
14 |
15 | if (getMenubar.menuList.length === 0) {
16 | concatAllowRoutes()
17 |
18 | return to.fullPath
19 | }
20 | })
21 |
22 | router.afterEach(() => {
23 | done()
24 | })
25 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/router/asyncRouter.ts:
--------------------------------------------------------------------------------
1 | const modules = import.meta.glob('../views/**/**.vue')
2 | const components: IObject<() => Promise> = {
3 | LayoutHeader: (() => import('/@/layout/index.vue')) as unknown as () => Promise
4 | }
5 |
6 | Object.keys(modules).forEach(key => {
7 | const nameMatch = key.match(/^\.\.\/views\/(.+)\.vue/)
8 | if (!nameMatch) return
9 | if (nameMatch[1].includes('_Components')) return
10 | const indexMatch = nameMatch[1].match(/(.*)\/Index$/i)
11 | let name = indexMatch ? indexMatch[1] : nameMatch[1];
12 | [name] = name.split('/').splice(-1)
13 | components[name] = modules[key] as () => Promise
14 | })
15 |
16 | export {
17 | components
18 | }
19 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia'
2 | export const pinia = createPinia()
3 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/type/index.d.ts:
--------------------------------------------------------------------------------
1 | export { }
2 | declare global {
3 | interface IObject {
4 | [index: string]: T
5 | }
6 | interface ImportMetaEnv {
7 | VITE_APP_TITLE: string
8 | VITE_PORT: number
9 | VITE_PROXY: string
10 | VITE_ADMIN_VERSION: string
11 | }
12 | interface ITable {
13 | data: Array
14 | next_position: number,
15 | size: number
16 | }
17 | interface Window {
18 | basePath: string;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/type/shim.vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { defineComponent } from 'vue'
3 | const Component: ReturnType
4 | export default Component
5 | }
6 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/type/store/layout.ts:
--------------------------------------------------------------------------------
1 | export interface IMenubar {
2 | menuList: Array
3 | }
4 |
5 | export interface ILayout {
6 | menubar: IMenubar
7 | status: IStatus
8 | dtmVersion: string
9 | globalError: string
10 | }
11 |
12 | export interface IStatus {
13 | isLoading: boolean
14 | }
15 |
16 | export interface IMenubarList {
17 | parentId?: number | string
18 | id?: number | string
19 | name: string
20 | path: string
21 | redirect?: string
22 | meta: {
23 | icon?: string
24 | title: string
25 | permission?: string[]
26 | activeMenu?: string
27 | hidden?: boolean
28 | alwaysShow?: boolean
29 | }
30 | component: (() => Promise) | string
31 | children?: Array
32 | }
33 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/utils/request.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const request = axios.create({
4 | timeout: 60000
5 | })
6 |
7 | export default request
8 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/utils/util.ts:
--------------------------------------------------------------------------------
1 | import { useRoute } from 'vue-router'
2 | import { IMenubarList } from '../type/store/layout'
3 |
4 | export const findCurrentMenubar = (menuList: IMenubarList[], root?: boolean) => {
5 | const route = useRoute()
6 | let arr: IMenubarList[] | IMenubarList = []
7 | for (let i = 0; i < menuList.length; i++) {
8 | const v = menuList[i]
9 | const usePath = v.meta.activeMenu || v.redirect || v.path
10 | const pos = usePath.lastIndexOf('/')
11 | const rootPath = pos == 0 ? usePath : usePath.substring(0, pos)
12 | if (route.path.indexOf(rootPath) !== -1) {
13 | if (!root) {
14 | arr = v.children as IMenubarList[]
15 | } else {
16 | arr = v
17 | }
18 | break
19 | }
20 | }
21 |
22 | return arr
23 | }
24 |
25 | export const sleep = async(ms: number) => {
26 | return new Promise(resolve => setTimeout(resolve, ms))
27 | }
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/views/Dashboard/GlobalTransactions/UnfinishedTransactions.vue:
--------------------------------------------------------------------------------
1 |
2 | Coming Soon
3 |
4 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/src/views/Dashboard/Nodes/LivingNodes.vue:
--------------------------------------------------------------------------------
1 |
2 | Coming Soon
3 |
4 |
5 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
3 | theme: {
4 | extend: {}
5 | },
6 | plugins: []
7 | }
8 |
--------------------------------------------------------------------------------
/dtm/dtm/admin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "useDefineForClassFields": true,
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "strict": true,
8 | "jsx": "preserve",
9 | "sourceMap": true,
10 | "resolveJsonModule": true,
11 | "esModuleInterop": true,
12 | "baseUrl": ".",
13 | "paths": {
14 | "/@/*": ["src/*"],
15 | },
16 | "lib": ["esnext", "dom"],
17 | "types": ["vite/client", "node"]
18 | },
19 | "include": ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.vue"],
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/dtm/dtm/charts/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/dtm/dtm/charts/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: dtm
3 | description: A Helm chart for Kubernetes
4 |
5 | # A chart can be either an 'application' or a 'library' chart.
6 | #
7 | # Application charts are a collection of templates that can be packaged into versioned archives
8 | # to be deployed.
9 | #
10 | # Library charts provide useful utilities or functions for the chart developer. They're included as
11 | # a dependency of application charts to inject those utilities and functions into the rendering
12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed.
13 | type: application
14 |
15 | # This is the chart version. This version number should be incremented each time you make changes
16 | # to the chart and its templates, including the app version.
17 | # Versions are expected to follow Semantic Versioning (https://semver.org/)
18 | version: 0.1.0
19 |
20 | # This is the version number of the application being deployed. This version number should be
21 | # incremented each time you make changes to the application. Versions are not expected to
22 | # follow Semantic Versioning. They should reflect the version the application is using.
23 | # It is recommended to use it with quotes.
24 | appVersion: "1.12.2"
25 |
--------------------------------------------------------------------------------
/dtm/dtm/charts/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: {{ include "dtm.fullname" . }}-conf
5 | labels:
6 | {{- include "dtm.labels" . | nindent 4 }}
7 | data:
8 | config.yaml: |-
9 | {{- .Values.configuration | nindent 4 }}
--------------------------------------------------------------------------------
/dtm/dtm/charts/templates/hpa.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.autoscaling.enabled }}
2 | apiVersion: autoscaling/v2beta1
3 | kind: HorizontalPodAutoscaler
4 | metadata:
5 | name: {{ include "dtm.fullname" . }}
6 | labels:
7 | {{- include "dtm.labels" . | nindent 4 }}
8 | spec:
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: {{ include "dtm.fullname" . }}
13 | minReplicas: {{ .Values.autoscaling.minReplicas }}
14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15 | metrics:
16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
17 | - type: Resource
18 | resource:
19 | name: cpu
20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
21 | {{- end }}
22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
23 | - type: Resource
24 | resource:
25 | name: memory
26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
27 | {{- end }}
28 | {{- end }}
29 |
--------------------------------------------------------------------------------
/dtm/dtm/charts/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: {{ include "dtm.fullname" . }}
5 | labels:
6 | {{- include "dtm.labels" . | nindent 4 }}
7 | spec:
8 | type: {{ .Values.service.type }}
9 | ports:
10 | - port: {{ .Values.service.ports.http }}
11 | targetPort: http
12 | protocol: TCP
13 | name: http
14 | - port: {{ .Values.service.ports.grpc }}
15 | targetPort: grpc
16 | protocol: TCP
17 | name: grpc
18 | selector:
19 | {{- include "dtm.selectorLabels" . | nindent 4 }}
20 |
--------------------------------------------------------------------------------
/dtm/dtm/charts/templates/tests/test-connection.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: "{{ include "dtm.fullname" . }}-test-connection"
5 | labels:
6 | {{- include "dtm.labels" . | nindent 4 }}
7 | annotations:
8 | "helm.sh/hook": test
9 | spec:
10 | containers:
11 | - name: wget
12 | image: busybox
13 | command: ['wget']
14 | args: ['{{ include "dtm.fullname" . }}:{{ .Values.service.port }}']
15 | restartPolicy: Never
16 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/cover_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmcli
8 |
9 | import (
10 | "net/url"
11 | "testing"
12 |
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | func TestQuery(t *testing.T) {
17 | qs, err := url.ParseQuery("a=b")
18 | assert.Nil(t, err)
19 | _, err = XaFromQuery(qs)
20 | assert.Error(t, err)
21 | _, err = TccFromQuery(qs)
22 | assert.Error(t, err)
23 | _, err = BarrierFromQuery(qs)
24 | assert.Error(t, err)
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/dtmimp/README-cn.md:
--------------------------------------------------------------------------------
1 | ## 注意
2 | 此包带imp后缀,主要被dtm内部使用,相关接口可能会发生变更,请勿使用这里的接口
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/dtmimp/README.md:
--------------------------------------------------------------------------------
1 | ## Notice
2 | Please donot use this package, and this package should only be used in dtm internally. The interfaces are not stable, and package name has postfix "imp"
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/dtmimp/db_special_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmimp
8 |
9 | import (
10 | "testing"
11 |
12 | "github.com/stretchr/testify/assert"
13 | )
14 |
15 | func TestDBSpecial(t *testing.T) {
16 | old := currentDBType
17 | assert.Error(t, CatchP(func() {
18 | SetCurrentDBType("no-driver")
19 | }))
20 | SetCurrentDBType(DBTypeMysql)
21 | sp := GetDBSpecial(DBTypeMysql)
22 |
23 | assert.Equal(t, "? ?", sp.GetPlaceHoldSQL("? ?"))
24 | assert.Equal(t, "xa start 'xa1'", sp.GetXaSQL("start", "xa1"))
25 | assert.Equal(t, "insert ignore into a(f) values(?)", sp.GetInsertIgnoreTemplate("a(f) values(?)", "c"))
26 | SetCurrentDBType(DBTypePostgres)
27 | sp = GetDBSpecial(DBTypePostgres)
28 | assert.Equal(t, "$1 $2", sp.GetPlaceHoldSQL("? ?"))
29 | assert.Equal(t, "begin", sp.GetXaSQL("start", "xa1"))
30 | assert.Equal(t, "insert into a(f) values(?) on conflict ON CONSTRAINT c do nothing", sp.GetInsertIgnoreTemplate("a(f) values(?)", "c"))
31 | SetCurrentDBType(old)
32 | }
33 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/dtmimp/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmimp
8 |
9 | import "database/sql"
10 |
11 | // DB interface of dtmcli db
12 | type DB interface {
13 | Exec(query string, args ...interface{}) (sql.Result, error)
14 | QueryRow(query string, args ...interface{}) *sql.Row
15 | }
16 |
17 | // DBConf defines db config
18 | type DBConf struct {
19 | Driver string `yaml:"Driver"`
20 | Host string `yaml:"Host"`
21 | Port int64 `yaml:"Port"`
22 | User string `yaml:"User"`
23 | Password string `yaml:"Password"`
24 | Db string `yaml:"Db"`
25 | Schema string `yaml:"Schema"`
26 | }
27 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/dtmimp/types_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmimp
8 |
9 | import (
10 | "testing"
11 |
12 | "github.com/stretchr/testify/assert"
13 | )
14 |
15 | func TestTypes(t *testing.T) {
16 | err := CatchP(func() {
17 | idGen := BranchIDGen{BranchID: "12345678901234567890123"}
18 | idGen.NewSubBranchID()
19 | })
20 | assert.Error(t, err)
21 | err = CatchP(func() {
22 | idGen := BranchIDGen{subBranchID: 99}
23 | idGen.NewSubBranchID()
24 | })
25 | assert.Error(t, err)
26 | }
27 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/logger/logger.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "github.com/dtm-labs/logger"
5 | )
6 |
7 | var (
8 | // WithLogger replaces default logger
9 | WithLogger = logger.WithLogger
10 | // InitLog is an initialization for a logger
11 | // level can be: debug info warn error
12 | InitLog = logger.InitLog
13 | // InitLog2 specify advanced log config
14 | InitLog2 = logger.InitLog2
15 | // Debugf log to level debug
16 | Debugf = logger.Debugf
17 |
18 | // Infof log to level info
19 | Infof = logger.Infof
20 |
21 | // Warnf log to level warn
22 | Warnf = logger.Warnf
23 | // Errorf log to level error
24 | Errorf = logger.Errorf
25 |
26 | // FatalfIf log to level error
27 | FatalfIf = logger.FatalfIf
28 |
29 | // FatalIfError if err is not nil, then log to level fatal and call os.Exit
30 | FatalIfError = logger.FatalIfError
31 | )
32 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmcli/types_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmcli
8 |
9 | import (
10 | "net/url"
11 | "testing"
12 |
13 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
14 | "github.com/stretchr/testify/assert"
15 | )
16 |
17 | func TestTypes(t *testing.T) {
18 | err := dtmimp.CatchP(func() {
19 | MustGenGid("http://localhost:36789/api/no")
20 | })
21 | assert.Error(t, err)
22 | assert.Error(t, err)
23 | _, err = BarrierFromQuery(url.Values{})
24 | assert.Error(t, err)
25 |
26 | }
27 |
28 | func TestXaSqlTimeout(t *testing.T) {
29 | SetBarrierTableName(dtmimp.BarrierTableName) // just cover this func
30 | }
31 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmgrpc/barrier.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmgrpc
8 |
9 | import (
10 | "context"
11 |
12 | "github.com/dtm-labs/dtm/client/dtmcli"
13 | "github.com/dtm-labs/dtm/client/dtmgrpc/dtmgimp"
14 | )
15 |
16 | // BarrierFromGrpc generate a Barrier from grpc context
17 | func BarrierFromGrpc(ctx context.Context) (*dtmcli.BranchBarrier, error) {
18 | tb := dtmgimp.TransBaseFromGrpc(ctx)
19 | return dtmcli.BarrierFrom(tb.TransType, tb.Gid, tb.BranchID, tb.Op)
20 | }
21 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmgrpc/dtmgimp/README-cn.md:
--------------------------------------------------------------------------------
1 | ## 注意
2 | 此包带imp后缀,主要被dtm内部使用,相关接口可能会发生变更,请勿使用这里的接口
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmgrpc/dtmgimp/README.md:
--------------------------------------------------------------------------------
1 | ## Notice
2 | Please donot use this package, and this package should only be used in dtm internally. The interfaces are not stable, and package name has postfix "imp"
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmgrpc/options.go:
--------------------------------------------------------------------------------
1 | package dtmgrpc
2 |
3 | import (
4 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
5 | )
6 |
7 | // TransBaseOption setup func for TransBase
8 | type TransBaseOption func(tb *dtmimp.TransBase)
9 |
10 | // WithBranchHeaders setup TransBase.BranchHeaders
11 | func WithBranchHeaders(headers map[string]string) TransBaseOption {
12 | return func(tb *dtmimp.TransBase) {
13 | tb.BranchHeaders = headers
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/dtm/dtm/client/dtmgrpc/type_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmgrpc
8 |
9 | import (
10 | "context"
11 | "testing"
12 |
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | func TestType(t *testing.T) {
17 | _, err := BarrierFromGrpc(context.Background())
18 | assert.Error(t, err)
19 |
20 | _, err = TccFromGrpc(context.Background())
21 | assert.Error(t, err)
22 |
23 | err = UseDriver("default")
24 | assert.Nil(t, err)
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm/client/workflow/dummyReadCloser.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | )
7 |
8 | // NewRespBodyFromBytes creates an io.ReadCloser from a byte slice
9 | // that is suitable for use as an http response body.
10 | func NewRespBodyFromBytes(body []byte) io.ReadCloser {
11 | return &dummyReadCloser{body: bytes.NewReader(body)}
12 | }
13 |
14 | type dummyReadCloser struct {
15 | body io.ReadSeeker
16 | }
17 |
18 | func (d *dummyReadCloser) Read(p []byte) (n int, err error) {
19 | return d.body.Read(p)
20 | }
21 |
22 | func (d *dummyReadCloser) Close() error {
23 | _, _ = d.body.Seek(0, io.SeekEnd)
24 | return nil
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm/client/workflow/factory.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/dtm-labs/logger"
8 | )
9 |
10 | type workflowFactory struct {
11 | protocol string
12 | httpDtm string
13 | httpCallback string
14 | grpcDtm string
15 | grpcCallback string
16 | handlers map[string]*wfItem
17 | }
18 |
19 | var defaultFac = workflowFactory{
20 | handlers: map[string]*wfItem{},
21 | }
22 |
23 | func (w *workflowFactory) execute(ctx context.Context, name string, gid string, data []byte) ([]byte, error) {
24 | handler := w.handlers[name]
25 | if handler == nil {
26 | return nil, fmt.Errorf("workflow '%s' not registered. please register at startup", name)
27 | }
28 | wf := w.newWorkflow(ctx, name, gid, data)
29 | for _, fn := range handler.custom {
30 | fn(wf)
31 | }
32 | return wf.process(handler.fn, data)
33 | }
34 |
35 | func (w *workflowFactory) register(name string, handler WfFunc2, custom ...func(wf *Workflow)) error {
36 | e := w.handlers[name]
37 | if e != nil {
38 | return fmt.Errorf("a handler already exists for %s", name)
39 | }
40 | logger.Debugf("workflow '%s' registered.", name)
41 | w.handlers[name] = &wfItem{
42 | fn: handler,
43 | custom: custom,
44 | }
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/dtm/dtm/client/workflow/server.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
7 | "github.com/dtm-labs/dtm/client/dtmgrpc"
8 | "github.com/dtm-labs/dtm/client/dtmgrpc/dtmgimp"
9 | "github.com/dtm-labs/dtm/client/workflow/wfpb"
10 | "google.golang.org/grpc/codes"
11 | "google.golang.org/grpc/status"
12 | "google.golang.org/protobuf/types/known/emptypb"
13 | )
14 |
15 | type workflowServer struct {
16 | wfpb.UnimplementedWorkflowServer
17 | }
18 |
19 | func (s *workflowServer) Execute(ctx context.Context, wd *wfpb.WorkflowData) (*emptypb.Empty, error) {
20 | if defaultFac.protocol != dtmimp.ProtocolGRPC {
21 | return nil, status.Errorf(codes.Internal, "workflow server not inited. please call workflow.InitGrpc first")
22 | }
23 | tb := dtmgimp.TransBaseFromGrpc(ctx)
24 | _, err := defaultFac.execute(ctx, tb.Op, tb.Gid, wd.Data)
25 | return &emptypb.Empty{}, dtmgrpc.DtmError2GrpcError(err)
26 | }
27 |
--------------------------------------------------------------------------------
/dtm/dtm/client/workflow/wfpb/wf.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option go_package = "./wfpb";
4 | import "google/protobuf/empty.proto";
5 |
6 | package workflow;
7 |
8 | // The Workflow service definition.
9 | service Workflow {
10 | rpc Execute(WorkflowData) returns (google.protobuf.Empty) {}
11 | }
12 |
13 | message WorkflowData {
14 | bytes Data = 1;
15 | }
16 |
--------------------------------------------------------------------------------
/dtm/dtm/client/workflow/workflow_test.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestAbnormal(t *testing.T) {
12 | fname := dtmimp.GetFuncName()
13 | _, err := defaultFac.execute(context.Background(), fname, fname, nil)
14 | assert.Error(t, err)
15 |
16 | err = defaultFac.register(fname, func(wf *Workflow, data []byte) ([]byte, error) { return nil, nil })
17 | assert.Nil(t, err)
18 | err = defaultFac.register(fname, nil)
19 | assert.Error(t, err)
20 |
21 | ws := &workflowServer{}
22 | _, err = ws.Execute(context.Background(), nil)
23 | assert.Contains(t, err.Error(), "call workflow.InitGrpc first")
24 | }
25 |
--------------------------------------------------------------------------------
/dtm/dtm/dtmsvr/microservices/drivers.go:
--------------------------------------------------------------------------------
1 | package microservices
2 |
3 | import (
4 | // load the microserver drivers
5 | _ "github.com/dtm-labs/dtmdriver-dapr"
6 | _ "github.com/dtm-labs/dtmdriver-ego"
7 | _ "github.com/dtm-labs/dtmdriver-gozero"
8 | _ "github.com/dtm-labs/dtmdriver-kratos"
9 | _ "github.com/dtm-labs/dtmdriver-polaris"
10 | _ "github.com/dtm-labs/dtmdriver-springcloud"
11 | _ "github.com/zhufuyi/dtmdriver-sponge"
12 | )
13 |
--------------------------------------------------------------------------------
/dtm/dtm/dtmsvr/storage/registry/factory.go:
--------------------------------------------------------------------------------
1 | package registry
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/dtm-labs/dtm/dtmsvr/storage"
7 | )
8 |
9 | // SingletonFactory is the factory to build store in SINGLETON pattern.
10 | type SingletonFactory struct {
11 | once sync.Once
12 |
13 | store storage.Store
14 |
15 | creatorFunction func() storage.Store
16 | }
17 |
18 | // GetStorage implement the StorageFactory.GetStorage
19 | func (f *SingletonFactory) GetStorage() storage.Store {
20 | f.once.Do(func() {
21 | f.store = f.creatorFunction()
22 | })
23 |
24 | return f.store
25 | }
26 |
--------------------------------------------------------------------------------
/dtm/dtm/dtmutil/consts.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package dtmutil
8 |
9 | const (
10 | // DefaultHTTPServer default url for http server. used by test and examples
11 | DefaultHTTPServer = "http://localhost:36789/api/dtmsvr"
12 | // DefaultJrpcServer default url for http json-rpc server. used by test and examples
13 | DefaultJrpcServer = "http://localhost:36789/api/json-rpc"
14 | // DefaultGrpcServer default url for grpc server. used by test and examples
15 | DefaultGrpcServer = "localhost:36790"
16 | )
17 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | # .goreleaser.yml
2 | project_name: dtm
3 | builds:
4 | - id: dtm_amd64
5 | env: [CGO_ENABLED=0]
6 | goos:
7 | - linux
8 | - windows
9 | - darwin
10 | goarch:
11 | - amd64
12 | dir: .
13 | main: main.go
14 | ldflags:
15 | - -s -w -X main.Version=v{{.Version}}
16 | - id: dtm_arm64
17 | env: [CGO_ENABLED=0]
18 | goos:
19 | - darwin
20 | goarch:
21 | - arm64
22 | dir: .
23 | main: main.go
24 | ldflags:
25 | - -s -w -X main.Version=v{{.Version}}
26 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/Dockerfile-release:
--------------------------------------------------------------------------------
1 | # syntax=docker/dockerfile:1
2 | # FROM node:14.19-alpine as builder1
3 | # ARG RELEASE_VERSION
4 | # WORKDIR /app/dtm
5 | # COPY . .
6 | # RUN cd admin && yarn && VITE_ADMIN_VERSION=$RELEASE_VERSION yarn build
7 |
8 | FROM --platform=amd64 node as builder2
9 | ARG TARGETARCH
10 | ARG TARGETOS
11 | ARG RELEASE_VERSION
12 | WORKDIR /app/dtm
13 | COPY . .
14 | RUN cd admin && yarn && VITE_ADMIN_VERSION=$RELEASE_VERSION yarn build
15 |
16 | FROM --platform=$TARGETPLATFORM golang:1.18-alpine as builder1
17 | ARG TARGETARCH
18 | ARG TARGETOS
19 | ARG RELEASE_VERSION
20 | WORKDIR /app/dtm
21 | # RUN go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
22 | COPY . .
23 | COPY --from=builder2 /app/dtm/admin/dist /app/dtm/admin/dist
24 | RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X main.Version=$RELEASE_VERSION"
25 |
26 | FROM --platform=$TARGETPLATFORM alpine
27 | COPY --from=builder1 /app/dtm/dtm /app/dtm/
28 | WORKDIR /app/dtm
29 | EXPOSE 8080
30 | ENTRYPOINT ["/app/dtm/dtm"]
31 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/Makefile:
--------------------------------------------------------------------------------
1 | # All targets.
2 | default: bench
3 |
4 | # configure these paths according to you system
5 | bench: /usr/local/bin/go /etc/redis/redis.conf /usr/local/bin/docker-compose main.go
6 | rm -f ../conf.sample.yml
7 | go build -o bench
8 |
9 | go: /usr/local/bin/go
10 |
11 | redis: /etc/redis/redis.conf
12 |
13 | mysql: /usr/local/bin/docker-compose
14 |
15 | /usr/local/bin/go:
16 | wget https://golang.org/dl/go1.17.1.linux-amd64.tar.gz
17 | rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.1.linux-amd64.tar.gz && cp -f /usr/local/go/bin/go /usr/local/bin/go && rm go1.*
18 |
19 | /etc/redis/redis.conf:
20 | apt update
21 | apt install -y redis redis-tools
22 |
23 | /usr/local/bin/docker-compose:
24 | apt update
25 | apt install -y sysbench apache2-utils mysql-client-core-8.0
26 | curl -fsSL https://get.docker.com | sh
27 | curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
28 | chmod +x /usr/local/bin/docker-compose
29 | cd .. && docker-compose -f helper/compose.mysql.yml up -d && cd bench
30 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/prepare.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 | apt update
3 | apt install -y git
4 | git clone https://github.com/dtm-labs/dtm.git && cd dtm && git checkout alpha && cd bench && make
5 |
6 |
7 | echo 'all prepared. you shoud run following commands to test in different terminal'
8 | echo
9 | echo 'cd dtm && go run helper/bench/main.go redis|boltdb|db'
10 | echo 'cd dtm && ./helper/bench/test-redis|boltdb|mysql.sh'
11 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/setup-redis6.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 | apt update
3 | apt install -y software-properties-common
4 | add-apt-repository -y ppa:redislabs/redis
5 | apt install -y redis redis-tools
6 |
7 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/setup.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 |
3 | # install all commands needed
4 |
5 | apt update
6 | apt install -y sysbench apache2-utils mysql-client-core-8.0 redis redis-tools
7 |
8 | # install docker and docker-compose
9 | curl -fsSL https://get.docker.com -o get-docker.sh
10 | sh get-docker.sh
11 | curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
12 | chmod +x /usr/local/bin/docker-compose
13 |
14 | # install go
15 | wget https://golang.org/dl/go1.17.1.linux-amd64.tar.gz
16 | rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.1.linux-amd64.tar.gz && cp -f /usr/local/go/bin/go /usr/local/bin/go
17 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/test-boltdb.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 |
3 | set -x
4 |
5 | ab -n 50000 -c 10 "http://127.0.0.1:8083/api/busi_bench/benchEmptyUrl"
6 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/test-flash-sales.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 |
3 | set -x
4 |
5 | export LOG_LEVEL=fatal
6 | export STORE_DRIVER=redis
7 | export STORE_HOST=localhost
8 | export STORE_PORT=6379
9 | export BUSI_REDIS=localhost:6379
10 | ./bench redis &
11 | echo 'sleeping 3s for dtm bench to run up.' && sleep 3
12 | curl "http://127.0.0.1:8083/api/busi_bench/benchFlashSalesReset"
13 | ab -n 300000 -c 20 "http://127.0.0.1:8083/api/busi_bench/benchFlashSales"
14 | pkill bench
15 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/bench/test-redis.sh:
--------------------------------------------------------------------------------
1 | # !/bin/bash
2 |
3 | set -x
4 |
5 | export LOG_LEVEL=warn
6 | export STORE_DRIVER=redis
7 | export STORE_HOST=localhost
8 | export STORE_PORT=6379
9 | cd .. && bench/bench redis &
10 | echo 'sleeping 3s for dtm bench to run up.' && sleep 3
11 | ab -n 1000000 -c 10 "http://127.0.0.1:8083/api/busi_bench/benchEmptyUrl"
12 | pkill bench
13 |
14 | redis-benchmark -n 300000 SET 'abcdefg' 'ddddddd'
15 |
16 | redis-benchmark -n 300000 EVAL "redis.call('SET', 'abcdedf', 'ddddddd')" 0
17 |
18 | redis-benchmark -n 300000 EVAL "redis.call('SET', KEYS[1], ARGV[1])" 1 'aaaaaaaaa' 'bbbbbbbbbb'
19 |
20 | redis-benchmark -n 3000000 -P 50 SET 'abcdefg' 'ddddddd'
21 |
22 | redis-benchmark -n 300000 EVAL "for k=1, 10 do; redis.call('SET', KEYS[1], ARGV[1]);end" 1 'aaaaaaaaa' 'bbbbbbbbbb'
23 |
24 | redis-benchmark -n 300000 -P 50 EVAL "redis.call('SET', KEYS[1], ARGV[1])" 1 'aaaaaaaaa' 'bbbbbbbbbb'
25 |
26 | redis-benchmark -n 300000 EVAL "for k=1,10 do;local c = cjson.decode(ARGV[1]);end" 1 'aaaaaaaaa' '{"aaaaa":"bbbbb","b":1,"t":"2012-01-01 14:00:00"}'
27 |
28 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/compose.store.yml:
--------------------------------------------------------------------------------
1 | version: '3.3'
2 | services:
3 | mysql:
4 | image: 'mysql:5.7'
5 | volumes:
6 | - /etc/localtime:/etc/localtime:ro
7 | environment:
8 | MYSQL_ALLOW_EMPTY_PASSWORD: 1
9 | command:
10 | [
11 | '--character-set-server=utf8mb4',
12 | '--collation-server=utf8mb4_unicode_ci',
13 | ]
14 | ports:
15 | - '3306:3306'
16 | postgres:
17 | image: 'postgres:13'
18 | command: postgres --max_prepared_transactions=1000
19 | volumes:
20 | - /etc/localtime:/etc/localtime:ro
21 | environment:
22 | POSTGRES_PASSWORD: mysecretpassword
23 | POSTGRES_DB: dtm
24 |
25 | ports:
26 | - '5432:5432'
27 | redis:
28 | image: 'redis'
29 | volumes:
30 | - /etc/localtime:/etc/localtime:ro
31 | ports:
32 | - '6379:6379'
33 | mongo:
34 | image: yedf/mongo-rs
35 | volumes:
36 | - /etc/localtime:/etc/localtime:ro
37 | ports:
38 | - '27017:27017'
39 | sqlserver2019:
40 | image: mcr.microsoft.com/mssql/server:2019-latest
41 | volumes:
42 | - /etc/localtime:/etc/localtime:ro
43 | ports:
44 | - 1433:1433
45 | environment:
46 | - ACCEPT_EULA=Y
47 | - MSSQL_SA_PASSWORD=p@ssw0rd
48 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/golint.sh:
--------------------------------------------------------------------------------
1 | set -x
2 |
3 | go install github.com/mgechev/revive@latest && revive -config revive.toml ./...
4 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/sync-client.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | set -x
3 | ver=$1
4 | if [ x$ver == x ]; then
5 | echo please specify you version like vx.x.x;
6 | exit 1;
7 | fi
8 |
9 | if [ ${ver:0:1} != v ]; then
10 | echo please specify you version like vx.x.x;
11 | exit 1;
12 | fi
13 |
14 | cd ../client
15 | cp -rf ../dtm/client/* ./
16 | sed -i '' -e 's/dtm-labs\/dtm\//dtm-labs\//g' */*.go */*/*.go
17 |
18 | rm -rf */*_test.go */*/*_test.go */*log */*/*log
19 | go mod tidy
20 | go build || exit 1
21 |
22 | git add .
23 | git commit -m"update from dtm to version $ver"
24 | git push
25 | git tag $ver
26 | git push --tags
27 |
28 | cd ../quick-start-sample
29 |
30 | go get -u github.com/dtm-labs/client@$ver
31 | go mod tidy
32 | go build || exit 1
33 | git add .
34 | git commit -m"update from dtm to version $ver"
35 | git push
36 |
37 |
--------------------------------------------------------------------------------
/dtm/dtm/helper/test-cover.sh:
--------------------------------------------------------------------------------
1 | set -x
2 | export DTM_DEBUG=1
3 | echo "mode: count" > coverage.txt
4 | for store in redis boltdb mysql postgres sqlserver; do
5 | TEST_STORE=$store go test -failfast -covermode count -coverprofile=profile.out -coverpkg=github.com/dtm-labs/dtm/client/dtmcli,github.com/dtm-labs/dtm/client/dtmcli/dtmimp,github.com/dtm-labs/logger,github.com/dtm-labs/dtm/client/dtmgrpc,github.com/dtm-labs/dtm/client/workflow,github.com/dtm-labs/dtm/client/dtmgrpc/dtmgimp,github.com/dtm-labs/dtm/dtmsvr,dtmsvr/config,github.com/dtm-labs/dtm/dtmsvr/storage,github.com/dtm-labs/dtm/dtmsvr/storage/boltdb,github.com/dtm-labs/dtm/dtmsvr/storage/redis,github.com/dtm-labs/dtm/dtmsvr/storage/registry,github.com/dtm-labs/dtm/dtmsvr/storage/sql,github.com/dtm-labs/dtm/dtmutil -gcflags=-l ./... || exit 1
6 | echo "TEST_STORE=$store finished"
7 | if [ -f profile.out ]; then
8 | cat profile.out | grep -v 'mode:' >> coverage.txt
9 | echo > profile.out
10 | fi
11 | done
12 | ## for local unit test, you may use following command
13 | # SKIP_MONGO=1 TEST_STORE=redis GOARCH=amd64 go test -v -failfast -count=1 -gcflags=all=-l ./...
14 |
15 | # go tool cover -html=coverage.txt
16 |
17 | # curl -s https://codecov.io/bash | bash
18 |
--------------------------------------------------------------------------------
/dtm/dtm/qs/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package main
8 |
9 | import (
10 | "github.com/dtm-labs/dtm/test/busi"
11 | )
12 |
13 | func main() {
14 | busi.QsMain()
15 | }
16 |
--------------------------------------------------------------------------------
/dtm/dtm/revive.toml:
--------------------------------------------------------------------------------
1 | ignoreGeneratedHeader = false
2 | severity = "warning"
3 | confidence = 0.8
4 | errorCode = 0
5 | warningCode = 0
6 |
7 | [rule.blank-imports]
8 | [rule.context-as-argument]
9 | [rule.context-keys-type]
10 | [rule.dot-imports]
11 | [rule.error-return]
12 | [rule.error-strings]
13 | [rule.error-naming]
14 | [rule.exported]
15 | [rule.if-return]
16 | [rule.increment-decrement]
17 | [rule.var-naming]
18 | [rule.var-declaration]
19 | [rule.range]
20 | [rule.receiver-naming]
21 | [rule.time-naming]
22 | [rule.unexported-return]
23 | [rule.indent-error-flow]
24 | [rule.errorf]
25 | [rule.superfluous-else]
26 | [rule.unreachable-code]
27 | [rule.redefines-builtin-id]
--------------------------------------------------------------------------------
/dtm/dtm/sqls/busi.mongo.js:
--------------------------------------------------------------------------------
1 | use dtm_busi
2 | db.user_account.drop()
3 | db.user_account.createIndex({ user_id: NumberLong(1) }, { unique: true })
4 |
5 | db.user_account.insert({ user_id: NumberLong(1), balance: 10000 })
6 | db.user_account.insert({ user_id: NumberLong(2), balance: 10000 })
7 |
--------------------------------------------------------------------------------
/dtm/dtm/sqls/busi.mysql.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE if not exists dtm_busi
2 | /*!40100 DEFAULT CHARACTER SET utf8mb4 */
3 | ;
4 | drop table if exists dtm_busi.user_account;
5 | create table if not exists dtm_busi.user_account(
6 | id int(11) PRIMARY KEY AUTO_INCREMENT,
7 | user_id int(11) UNIQUE,
8 | balance DECIMAL(10, 2) not null default '0',
9 | trading_balance DECIMAL(10, 2) not null default '0',
10 | create_time datetime DEFAULT now(),
11 | update_time datetime DEFAULT now(),
12 | key(create_time),
13 | key(update_time)
14 | ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
15 | insert into dtm_busi.user_account (user_id, balance)
16 | values (1, 10000),
17 | (2, 10000) on DUPLICATE KEY
18 | UPDATE balance =
19 | values (balance);
--------------------------------------------------------------------------------
/dtm/dtm/sqls/busi.postgres.sql:
--------------------------------------------------------------------------------
1 | CREATE SCHEMA if not exists dtm_busi
2 | /* SQLINES DEMO *** RACTER SET utf8mb4 */
3 | ;
4 | drop table if exists dtm_busi.user_account;
5 | -- SQLINES LICENSE FOR EVALUATION USE ONLY
6 | create sequence if not exists dtm_busi.user_account_seq;
7 | create table if not exists dtm_busi.user_account(
8 | id int PRIMARY KEY DEFAULT NEXTVAL ('dtm_busi.user_account_seq'),
9 | user_id int UNIQUE,
10 | balance DECIMAL(10, 2) not null default '0',
11 | trading_balance DECIMAL(10, 2) not null default '0',
12 | create_time timestamp(0) with time zone DEFAULT now(),
13 | update_time timestamp(0) with time zone DEFAULT now()
14 | );
15 | -- SQLINES LICENSE FOR EVALUATION USE ONLY
16 | create index if not exists create_idx on dtm_busi.user_account(create_time);
17 | -- SQLINES LICENSE FOR EVALUATION USE ONLY
18 | create index if not exists update_idx on dtm_busi.user_account(update_time);
19 | TRUNCATE dtm_busi.user_account;
20 | insert into dtm_busi.user_account (user_id, balance)
21 | values (1, 10000),
22 | (2, 10000);
--------------------------------------------------------------------------------
/dtm/dtm/sqls/dtmcli.barrier.mongo.js:
--------------------------------------------------------------------------------
1 | use dtm_barrier
2 | db.barrier.drop()
3 | db.barrier.createIndex({ gid: 1, branch_id: 1, op: 1, barrier_id: 1 }, { unique: true })
4 | db.barrier.insert({ gid: "123", branch_id: "01", op: "action", barrier_id: "01", reason: "test" });
5 |
--------------------------------------------------------------------------------
/dtm/dtm/sqls/dtmcli.barrier.mysql.sql:
--------------------------------------------------------------------------------
1 | create database if not exists dtm_barrier
2 | /*!40100 DEFAULT CHARACTER SET utf8mb4 */
3 | ;
4 | drop table if exists dtm_barrier.barrier;
5 | create table if not exists dtm_barrier.barrier(
6 | id bigint(22) PRIMARY KEY AUTO_INCREMENT,
7 | trans_type varchar(45) default '',
8 | gid varchar(128) default '',
9 | branch_id varchar(128) default '',
10 | op varchar(45) default '',
11 | barrier_id varchar(45) default '',
12 | reason varchar(45) default '' comment 'the branch type who insert this record',
13 | create_time datetime DEFAULT now(),
14 | update_time datetime DEFAULT now(),
15 | key(create_time),
16 | key(update_time),
17 | UNIQUE key(gid, branch_id, op, barrier_id)
18 | ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
--------------------------------------------------------------------------------
/dtm/dtm/sqls/dtmcli.barrier.postgres.sql:
--------------------------------------------------------------------------------
1 | create schema if not exists dtm_barrier;
2 | drop table if exists dtm_barrier.barrier;
3 | CREATE SEQUENCE if not EXISTS dtm_barrier.barrier_seq;
4 | create table if not exists dtm_barrier.barrier(
5 | id bigint NOT NULL DEFAULT NEXTVAL ('dtm_barrier.barrier_seq'),
6 | trans_type varchar(45) default '',
7 | gid varchar(128) default '',
8 | branch_id varchar(128) default '',
9 | op varchar(45) default '',
10 | barrier_id varchar(45) default '',
11 | reason varchar(45) default '',
12 | create_time timestamp(0) with time zone DEFAULT NULL,
13 | update_time timestamp(0) with time zone DEFAULT NULL,
14 | PRIMARY KEY(id),
15 | CONSTRAINT uniq_barrier unique(gid, branch_id, op, barrier_id)
16 | );
--------------------------------------------------------------------------------
/dtm/dtm/test/busi/base_jrpc.go:
--------------------------------------------------------------------------------
1 | package busi
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
7 | "github.com/dtm-labs/dtm/dtmutil"
8 | "github.com/dtm-labs/logger"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | // BusiJrpcURL url prefix for busi
13 | var BusiJrpcURL = fmt.Sprintf("http://localhost:%d/api/json-rpc?method=", BusiPort)
14 |
15 | func addJrpcRoute(app *gin.Engine) {
16 | app.POST("/api/json-rpc", dtmutil.WrapHandler(func(c *gin.Context) interface{} {
17 | var data map[string]interface{}
18 | err := c.BindJSON(&data)
19 | dtmimp.E2P(err)
20 | logger.Debugf("method is: %s", data["method"])
21 | var rerr map[string]interface{}
22 | r := MainSwitch.JrpcResult.Fetch()
23 | if r != "" {
24 | rerr = map[string]interface{}{
25 | "code": map[string]int{
26 | "FAILURE": dtmimp.JrpcCodeFailure,
27 | "ONGOING": dtmimp.JrpcCodeOngoing,
28 | "OTHER": -23977,
29 | },
30 | }
31 | }
32 | return map[string]interface{}{
33 | "jsonrpc": "2.0",
34 | "error": rerr,
35 | "id": data["id"],
36 | }
37 | }))
38 | }
39 |
--------------------------------------------------------------------------------
/dtm/dtm/test/busi/startup.go:
--------------------------------------------------------------------------------
1 | package busi
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | grpc "google.golang.org/grpc"
6 | )
7 |
8 | // Startup startup the busi's grpc and http service
9 | func Startup() (*gin.Engine, *grpc.Server) {
10 | svr := GrpcStartup()
11 | app := BaseAppStartup()
12 | return app, svr
13 | }
14 |
--------------------------------------------------------------------------------
/dtm/dtm/test/tcc_jrpc_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/dtm-labs/dtm/client/dtmcli"
7 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
8 | "github.com/dtm-labs/dtm/dtmutil"
9 | "github.com/dtm-labs/dtm/test/busi"
10 | "github.com/go-resty/resty/v2"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestTccJrpcNormal(t *testing.T) {
15 | req := busi.GenReqHTTP(30, false, false)
16 | gid := dtmimp.GetFuncName()
17 | err := dtmcli.TccGlobalTransaction2(dtmutil.DefaultJrpcServer, gid, func(tcc *dtmcli.Tcc) {
18 | tcc.Protocol = dtmimp.Jrpc
19 | }, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
20 | _, err := tcc.CallBranch(req, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
21 | assert.Nil(t, err)
22 | return tcc.CallBranch(req, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
23 | })
24 | assert.Nil(t, err)
25 | waitTransProcessed(gid)
26 | assert.Equal(t, StatusSucceed, getTransStatus(gid))
27 | assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(gid))
28 | }
29 |
--------------------------------------------------------------------------------
/dtm/dtm/test/workflow_base_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021 yedf. All rights reserved.
3 | * Use of this source code is governed by a BSD-style
4 | * license that can be found in the LICENSE file.
5 | */
6 |
7 | package test
8 |
9 | import (
10 | "testing"
11 | "time"
12 |
13 | "github.com/dtm-labs/dtm/client/dtmcli"
14 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
15 | "github.com/dtm-labs/dtm/dtmsvr"
16 | "github.com/dtm-labs/dtm/dtmsvr/storage"
17 | "github.com/stretchr/testify/assert"
18 | )
19 |
20 | func TestWorkflowBranchConflict(t *testing.T) {
21 | gid := dtmimp.GetFuncName()
22 | store := dtmsvr.GetStore()
23 | now := time.Now()
24 | g := &storage.TransGlobalStore{
25 | Gid: gid,
26 | Status: dtmcli.StatusPrepared,
27 | NextCronTime: &now,
28 | }
29 | err := store.MaySaveNewTrans(g, []storage.TransBranchStore{
30 | {
31 | BranchID: "00",
32 | Op: dtmimp.OpAction,
33 | },
34 | })
35 | assert.Nil(t, err)
36 | err = dtmimp.CatchP(func() {
37 | store.LockGlobalSaveBranches(gid, dtmcli.StatusPrepared, []storage.TransBranchStore{
38 | {BranchID: "00", Op: dtmimp.OpAction},
39 | }, -1)
40 | })
41 | assert.Error(t, err)
42 | store.ChangeGlobalStatus(g, StatusSucceed, []string{}, true)
43 | }
44 |
--------------------------------------------------------------------------------
/dtm/dtm/test/workflow_http_ret_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
7 | "github.com/dtm-labs/dtm/client/workflow"
8 | "github.com/dtm-labs/dtm/test/busi"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestWorkflowRet(t *testing.T) {
13 | workflow.SetProtocolForTest(dtmimp.ProtocolHTTP)
14 | req := busi.GenReqHTTP(30, false, false)
15 | gid := dtmimp.GetFuncName()
16 |
17 | workflow.Register2(gid, func(wf *workflow.Workflow, data []byte) ([]byte, error) {
18 | var req busi.ReqHTTP
19 | dtmimp.MustUnmarshal(data, &req)
20 | _, err := wf.NewBranch().NewRequest().SetBody(req).Post(Busi + "/TransOut")
21 | return []byte("result of workflow"), err
22 | })
23 |
24 | ret, err := workflow.Execute2(gid, gid, dtmimp.MustMarshal(req))
25 | assert.Nil(t, err)
26 | assert.Equal(t, "result of workflow", string(ret))
27 | assert.Equal(t, StatusSucceed, getTransStatus(gid))
28 |
29 | // the second execute will return result directly
30 | ret, err = workflow.Execute2(gid, gid, dtmimp.MustMarshal(req))
31 | assert.Nil(t, err)
32 | assert.Equal(t, "result of workflow", string(ret))
33 | assert.Equal(t, StatusSucceed, getTransStatus(gid))
34 | }
35 |
--------------------------------------------------------------------------------
/dtm/dtm/test/workflow_interceptor_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/dtm-labs/dtm/client/workflow"
8 | "github.com/stretchr/testify/assert"
9 | "google.golang.org/grpc"
10 | )
11 |
12 | func TestWorkflowInterceptorOutsideSaga(t *testing.T) {
13 | called := false
14 | workflow.Interceptor(context.TODO(), "method", nil, nil, &grpc.ClientConn{}, func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
15 | called = true
16 | return nil
17 | })
18 | assert.True(t, called)
19 | }
20 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | quick-start-sample
15 | # Dependency directories (remove the comment below to include it)
16 | # vendor/
17 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 DTM Development and Communities
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/README-cn.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README.md)
2 |
3 | # quick-start-sample
4 | dtm go 客户端[client](https://github.com/dtm-labs/client) 的最简单例子.
5 |
6 | 这个仓库包括了4个项目:
7 | - [dtmcli-qs](./dtmcli-qs/README-cn.md): 演示http客户端dtmcli的接入
8 | - [dtmgrpc-qs](./dtmgrpc-qs/README-cn.md): 演示grpc客户端dtmgrpc的接入
9 | - [workflow-http](./workflow-http/README-cn.md): 演示workflow的http接入
10 | - [workflow-grpc](./workflow-grpc/README-cn.md): 演示workflow的grpc接入
11 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/README.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](./README-cn.md)
2 |
3 | # quick-start-sample
4 | quick start sample for [client](https://github.com/dtm-labs/client) of dtm.
5 |
6 | This repo includes 4 project:
7 | - [dtmcli-qs](./dtmcli-qs/README.md): illustrate the usage of http client
8 | - [dtmgrpc-qs](./dtmgrpc-qs/README.md): illustrate the usage of grpc client
9 | - [workflow-http](./workflow-http/README.md): illustrate the usage of workflow using http
10 | - [workflow-grpc](./workflow-grpc/README.md): illustrate the usage of workflow using grpc
11 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/busi/busi.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package busi;
4 |
5 | option go_package = "./busi";
6 |
7 | // The dtm service definition.
8 | service Busi {
9 | rpc TransInRevert(BusiReq) returns (BusiReply) {}
10 | rpc TransOutRevert(BusiReq) returns (BusiReply) {}
11 |
12 | rpc TransIn(BusiReq) returns (BusiReply) {}
13 | rpc TransOut(BusiReq) returns (BusiReply) {}
14 | }
15 |
16 | message BusiReq {
17 | int64 Amount = 1;
18 | int64 UserID = 2;
19 | string TransOutResult = 3;
20 | string TransInResult = 4;
21 | }
22 |
23 | message BusiReply {
24 | string Message = 1;
25 | }
--------------------------------------------------------------------------------
/dtm/quick-start-sample/dtmcli-qs/README-cn.md:
--------------------------------------------------------------------------------
1 | # dtmcli-qs
2 | client/dtmcli的最简go使用示例
3 |
4 | ## 快速开始
5 |
6 | ### 安装运行dtm
7 |
8 | 参考[dtm安装运行](https://dtm.pub/guide/install.html)
9 |
10 | ### 启动示例
11 |
12 | ``` bash
13 | go run main.go
14 | ```
15 |
16 | ### 输出
17 |
18 | 可以从dtmcli-qs的日志里看到执行的顺序如下:
19 |
20 | - TransOut
21 | - TransIn
22 |
23 | 整个saga事务执行成功
24 |
25 | ### 示例解读
26 |
27 | ``` GO
28 | // 具体业务微服务地址
29 | const qsBusi = "http://localhost:8081/api/busi_saga"
30 | req := &gin.H{"amount": 30} // 微服务的载荷
31 | // DtmServer为DTM服务的地址,是一个url
32 | DtmServer := "http://localhost:36789/api/dtmsvr"
33 | saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
34 | // 添加一个TransOut的子事务,正向操作为url: qsBusi+"/TransOut", 补偿操作为url: qsBusi+"/TransOutCom"
35 | Add(qsBusi+"/TransOut", qsBusi+"/TransOutCom", req).
36 | // 添加一个TransIn的子事务,正向操作为url: qsBusi+"/TransIn", 补偿操作为url: qsBusi+"/TransInCom"
37 | Add(qsBusi+"/TransIn", qsBusi+"/TransInCom", req)
38 | // 提交saga事务,dtm会完成所有的子事务/回滚所有的子事务
39 | err := saga.Submit()
40 | ```
41 |
42 | ### 更多示例,详见[dtm-examples](https://github.com/dtm-labs/dtm-examples)
43 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/dtmgrpc-qs/README-cn.md:
--------------------------------------------------------------------------------
1 | # dtmgrpc-qs
2 | client/dtmgrpc的最简go使用示例
3 |
4 | ## 快速开始
5 |
6 | ### 安装运行dtm
7 |
8 | 参考[dtm安装运行](https://dtm.pub/guide/install.html)
9 |
10 | ### 启动示例
11 |
12 | ``` bash
13 | go run main.go
14 | ```
15 |
16 | ### 输出
17 |
18 | 可以从dtmcli-qs的日志里看到执行的顺序如下:
19 |
20 | - TransOut
21 | - TransIn
22 |
23 | 整个saga事务执行成功
24 |
25 | ### 示例解读
26 |
27 | ``` GO
28 | gid := shortuuid.New() // 生成gid
29 | req := &busi.BusiReq{Amount: 30} // 微服务的载荷
30 |
31 | saga := dtmgrpc.NewSagaGrpc(busi.DtmGrpcServer, gid).
32 | // 添加一个TransOut的子事务,正向操作为grpc的url: busi.BusiGrpc+"/busi.Busi/TransOut", 补偿操作类似
33 | Add(busi.BusiGrpc+"/busi.Busi/TransOut", busi.BusiGrpc+"/busi.Busi/TransOutRevert", req).
34 | // 添加一个TransIn的子事务,正向操作为grpc的url: busi.BusiGrpc+"/busi.Busi/TransIn", 补偿操作类似
35 | Add(busi.BusiGrpc+"/busi.Busi/TransIn", busi.BusiGrpc+"/busi.Busi/TransInRevert", req)
36 | // 提交saga事务,dtm会完成所有的子事务/回滚所有的子事务
37 | err := saga.Submit()
38 | ```
39 |
40 | ### 更多示例,详见[dtm-examples](https://github.com/dtm-labs/dtm-examples)
41 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/dtmgrpc-qs/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/dtm-labs/client/dtmcli/logger"
7 | "github.com/dtm-labs/client/dtmgrpc"
8 | "github.com/dtm-labs/quick-start-sample/busi"
9 | "github.com/lithammer/shortuuid/v3"
10 | )
11 |
12 | func main() {
13 | s := busi.GrpcNewServer()
14 | busi.GrpcStartup(s)
15 | logger.Infof("grpc simple transaction begin")
16 | gid := shortuuid.New()
17 | req := &busi.BusiReq{Amount: 30}
18 | // req := &busi.BusiReq{Amount: 30, TransInResult: "FAILURE"}
19 | saga := dtmgrpc.NewSagaGrpc(busi.DtmGrpcServer, gid).
20 | Add(busi.BusiGrpc+"/busi.Busi/TransOut", busi.BusiGrpc+"/busi.Busi/TransOutRevert", req).
21 | Add(busi.BusiGrpc+"/busi.Busi/TransIn", busi.BusiGrpc+"/busi.Busi/TransInRevert", req)
22 | err := saga.Submit()
23 | if err != nil {
24 | panic(err)
25 | }
26 | time.Sleep(3 * time.Second)
27 | }
28 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/dummy.go:
--------------------------------------------------------------------------------
1 | package quickstartsample
2 |
3 | import (
4 | _ "github.com/dtm-labs/client/dtmcli"
5 | _ "github.com/dtm-labs/client/dtmgrpc"
6 | _ "github.com/dtm-labs/client/workflow"
7 | _ "github.com/dtm-labs/quick-start-sample/busi"
8 | )
9 |
--------------------------------------------------------------------------------
/dtm/quick-start-sample/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/dtm-labs/quick-start-sample
2 |
3 | go 1.16
4 |
5 | // replace github.com/dtm-labs/client => ../client
6 |
7 | require (
8 | github.com/dtm-labs/client v1.17.3
9 | github.com/dtm-labs/logger v0.0.2 // indirect
10 | github.com/gin-gonic/gin v1.8.1
11 | github.com/klauspost/compress v1.16.5 // indirect
12 | github.com/lithammer/shortuuid/v3 v3.0.7
13 | github.com/montanaflynn/stats v0.7.1 // indirect
14 | github.com/xdg-go/scram v1.1.2 // indirect
15 | github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
16 | go.mongodb.org/mongo-driver v1.11.6 // indirect
17 | go.uber.org/atomic v1.11.0 // indirect
18 | go.uber.org/multierr v1.11.0 // indirect
19 | go.uber.org/zap v1.24.0 // indirect
20 | golang.org/x/crypto v0.9.0 // indirect
21 | golang.org/x/sync v0.2.0 // indirect
22 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
23 | google.golang.org/grpc v1.55.0
24 | google.golang.org/protobuf v1.30.0
25 | )
26 |
--------------------------------------------------------------------------------
/dtm/sql_dtm.sql:
--------------------------------------------------------------------------------
1 | create schema dtm_busi;
2 |
3 |
4 | CREATE SEQUENCE IF NOT EXISTS dtm_busi.user_account_id_seq
5 | INCREMENT 1
6 | START 1
7 | MINVALUE 1
8 | MAXVALUE 9223372036854775807
9 | CACHE 1;
10 | CREATE TABLE dtm_busi.user_account (
11 | id bigint NOT NULL DEFAULT nextval('dtm_busi.user_account_id_seq'::regclass) PRIMARY KEY,
12 | user_id bigint not NULL UNIQUE ,
13 | balance decimal(10,2) NOT NULL DEFAULT '0.00',
14 | trading_balance decimal(10,2) NOT NULL DEFAULT '0.00',
15 | create_time timestamp without time zone DEFAULT now(),
16 | update_time timestamp without time zone DEFAULT now()
17 | );
--------------------------------------------------------------------------------
/elsticsearch/README.md:
--------------------------------------------------------------------------------
1 | # elastic search
2 | ## account:
3 | ```
4 | elastic
5 | ZQjqfRh4X6gQZPgTgh4iv6n6
6 | ```
--------------------------------------------------------------------------------
/elsticsearch/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "open-dev/elsticsearch/query"
7 | )
8 |
9 | func main() {
10 | // query.AddDoc()
11 | query.Search()
12 | fmt.Println("add success")
13 | }
14 |
--------------------------------------------------------------------------------
/gin-web-framework/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/gin-web-framework/README.md
--------------------------------------------------------------------------------
/gin-web-framework/apiExample/index.go:
--------------------------------------------------------------------------------
1 | package apiexample
2 |
--------------------------------------------------------------------------------
/gin-web-framework/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
--------------------------------------------------------------------------------
/http/keep-alive/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | )
7 |
8 | func Index(w http.ResponseWriter, r *http.Request) {
9 | fmt.Println("receive a request from:", r.RemoteAddr, r.Header)
10 | w.Write([]byte("ok"))
11 | }
12 |
13 | func main() {
14 | fmt.Println("server keep alive")
15 | var s = http.Server{
16 | Addr: ":8080",
17 | Handler: http.HandlerFunc(Index),
18 | }
19 | s.SetKeepAlivesEnabled(false)
20 | s.ListenAndServe()
21 | }
22 |
--------------------------------------------------------------------------------
/http/request/http.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "net/http"
7 | "net/url"
8 | )
9 |
10 | func HttpRequest(
11 | urlStr string,
12 | method string,
13 | headers map[string]string,
14 | params map[string]string,
15 | data any) (*http.Response, error) {
16 | // 创建URL
17 | u, err := url.Parse(urlStr)
18 | if err != nil {
19 | return nil, err
20 | }
21 |
22 | // 添加查询参数
23 | query := u.Query()
24 | for k, v := range params {
25 | query.Set(k, v)
26 | }
27 | u.RawQuery = query.Encode()
28 |
29 | // 将数据编码为JSON
30 | buf := new(bytes.Buffer)
31 | if data != nil {
32 | b, err := json.Marshal(data)
33 | if err != nil {
34 | return nil, err
35 | }
36 | buf = bytes.NewBuffer(b)
37 | }
38 |
39 | // 创建请求
40 | req, err := http.NewRequest(method, u.String(), buf)
41 |
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | for k, v := range headers {
47 | req.Header.Set(k, v)
48 | }
49 |
50 | if data != nil {
51 | req.Header.Set("Content-Type", "application/json")
52 | }
53 |
54 | // 发送请求
55 | resp, err := http.DefaultClient.Do(req)
56 | if err != nil {
57 | return nil, err
58 | }
59 |
60 | // 返回响应,让调用者处理
61 | return resp, nil
62 | }
63 |
--------------------------------------------------------------------------------
/interview/devops/DevOps__1718418692.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/interview/devops/DevOps__1718418692.pdf
--------------------------------------------------------------------------------
/kafka/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/.DS_Store
--------------------------------------------------------------------------------
/kafka/images/at_least_once_delivery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/at_least_once_delivery.png
--------------------------------------------------------------------------------
/kafka/images/at_most_once_delivery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/at_most_once_delivery.png
--------------------------------------------------------------------------------
/kafka/images/consumer_group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/consumer_group.png
--------------------------------------------------------------------------------
/kafka/images/segment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/segment.png
--------------------------------------------------------------------------------
/kafka/images/segment1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/segment1.png
--------------------------------------------------------------------------------
/kafka/images/segment2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/segment2.png
--------------------------------------------------------------------------------
/kafka/images/segment3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/kafka/images/segment3.png
--------------------------------------------------------------------------------
/kafka/mskaws/README.md:
--------------------------------------------------------------------------------
1 | # demo aws msk
2 |
--------------------------------------------------------------------------------
/letgo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/.DS_Store
--------------------------------------------------------------------------------
/letgo/README.md:
--------------------------------------------------------------------------------
1 | # Lets Go
2 |
3 | ## Chapter 2.3: Web Application Basics
4 | - link: https://github.com/ducnpdev/open-dev/tree/master/letgo/chapter2.3
5 | ## Chapter 2.4: Routing Requests
6 | - link: https://github.com/ducnpdev/open-dev/tree/master/letgo/chapter2.4
7 |
--------------------------------------------------------------------------------
/letgo/chapter2.3/README.md:
--------------------------------------------------------------------------------
1 | # Lets Go
2 |
3 | ## Chapter 2.3: Web Application Basics
4 | - Đầu tiên cần 1 func handler, để xử lý logic. Giống như MVC, handler dùng để xử lý logic, nhận request từ client và response data thông qua HTTP.
5 |
6 | - Cần có 1 router, trong này mình dùng http.NewServeMux, sàu này có thể dùng Gin, Echo.
7 |
8 | - Sau cùng là 1 máy chủ, mục đích để dợi nhận request từ client, sau này có thể dùng Nginx hoặc Apache.
9 | ```go
10 | package main
11 | import (
12 | "log"
13 | "net/http"
14 | )
15 | func home(w http.ResponseWriter, r *http.Request) {
16 | w.Write([]byte("Hello from OpenDev"))
17 | }
18 | func main() {
19 | mux := http.NewServeMux()
20 | mux.HandleFunc("/", home)
21 | log.Println("Starting server on :4000")
22 | err := http.ListenAndServe(":4000", mux)
23 | log.Fatal(err)
24 | }
25 | ```
26 |
27 | - Chú ý: khi start `go run main.go` web sẽ lắng nghe trên port 4000, mở web tại đường dẫn: http://localhost:4000
--------------------------------------------------------------------------------
/letgo/chapter2.3/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.3/code.png
--------------------------------------------------------------------------------
/letgo/chapter2.3/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | // Define a home handler function which writes a byte slice containing
9 | // "Hello from Snippetbox" as the response body.
10 | func home(w http.ResponseWriter, r *http.Request) {
11 | w.Write([]byte("Hello from OpenDev"))
12 | }
13 | func main() {
14 | // Use the http.NewServeMux() function to initialize a new servemux, then
15 | // register the home function as the handler for the "/" URL pattern.
16 | mux := http.NewServeMux()
17 | mux.HandleFunc("/", home)
18 | // Use the http.ListenAndServe() function to start a new web server. We pas
19 | // two parameters: the TCP network address to listen on (in this case ":400
20 | // and the servemux we just created. If http.ListenAndServe() returns an er
21 | // we use the log.Fatal() function to log the error message and exit.
22 | log.Println("Starting server on :4000")
23 | err := http.ListenAndServe(":4000", mux)
24 | log.Fatal(err)
25 | }
26 |
--------------------------------------------------------------------------------
/letgo/chapter2.3/readme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.3/readme.png
--------------------------------------------------------------------------------
/letgo/chapter2.3/web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.3/web.png
--------------------------------------------------------------------------------
/letgo/chapter2.4/create_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.4/create_user.png
--------------------------------------------------------------------------------
/letgo/chapter2.4/list_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.4/list_user.png
--------------------------------------------------------------------------------
/letgo/chapter2.4/page_not_found.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.4/page_not_found.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/code.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/css_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/css_code.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/folder.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | )
7 |
8 | func fileStatis(w http.ResponseWriter, r *http.Request) {
9 | w.Write([]byte("danh sach user OpenDev..."))
10 | }
11 |
12 | func main() {
13 | // Use the http.NewServeMux() function to initialize a new servemux, then
14 | // register the home function as the handler for the "/" URL pattern.
15 | mux := http.NewServeMux()
16 |
17 | fileServer := http.FileServer(http.Dir("./ui/static/"))
18 | // Use the mux.Handle() function to register the file server as the handler
19 | // all URL paths that start with "/static/". For matching paths, we strip t
20 | // "/static" prefix before the request reaches the file server.
21 | mux.Handle("/static/", http.StripPrefix("/static", fileServer))
22 |
23 | log.Println("Starting server on :4000")
24 | err := http.ListenAndServe(":4000", mux)
25 | log.Fatal(err)
26 | }
27 |
--------------------------------------------------------------------------------
/letgo/chapter2.9/static_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/static_file.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/efs.go:
--------------------------------------------------------------------------------
1 | package ui
2 |
3 | import (
4 | "embed"
5 | )
6 |
7 | //go:embed "html" "static"
8 | var Files embed.FS
9 |
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/base.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{define "base"}}
4 |
5 |
6 |
7 |
8 | {{template "title" .}} - Snippetbox
9 |
10 |
11 |
12 |
13 |
14 |
17 | {{template "nav" .}}
18 |
19 | {{with .Flash}}
20 | {{.}}
21 | {{end}}
22 | {{template "main" .}}
23 |
24 |
27 |
28 |
29 |
30 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/pages/home.tmpl:
--------------------------------------------------------------------------------
1 | {{define "title"}}Home{{end}}
2 |
3 | {{define "main"}}
4 | Latest Snippets
5 | {{if .Snippets}}
6 |
7 |
8 | Title |
9 | Created |
10 | ID |
11 |
12 | {{range .Snippets}}
13 |
14 | {{.Title}} |
15 | {{humanDate .Created}} |
16 | #{{.ID}} |
17 |
18 | {{end}}
19 |
20 | {{else}}
21 | There's nothing to see here... yet!
22 | {{end}}
23 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/pages/login.tmpl:
--------------------------------------------------------------------------------
1 | {{define "title"}}Login{{end}}
2 |
3 | {{define "main"}}
4 |
27 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/pages/signup.tmpl:
--------------------------------------------------------------------------------
1 | {{define "title"}}Signup{{end}}
2 |
3 | {{define "main"}}
4 |
31 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/pages/view.tmpl:
--------------------------------------------------------------------------------
1 | {{define "title"}}Snippet #{{.Snippet.ID}}{{end}}
2 |
3 | {{define "main"}}
4 | {{with .Snippet}}
5 |
6 |
7 | {{.Title}}
8 | #{{.ID}}
9 |
10 |
{{.Content}}
11 |
12 |
13 |
14 |
15 |
16 | {{end}}
17 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/html/partials/nav.tmpl:
--------------------------------------------------------------------------------
1 | {{define "nav"}}
2 |
21 | {{end}}
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/ui/static/img/favicon.ico
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/static/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/letgo/chapter2.9/ui/static/img/logo.png
--------------------------------------------------------------------------------
/letgo/chapter2.9/ui/static/js/main.js:
--------------------------------------------------------------------------------
1 | var navLinks = document.querySelectorAll("nav a");
2 | for (var i = 0; i < navLinks.length; i++) {
3 | var link = navLinks[i]
4 | if (link.getAttribute('href') == window.location.pathname) {
5 | link.classList.add("live");
6 | break;
7 | }
8 | }
--------------------------------------------------------------------------------
/performances/README.MD:
--------------------------------------------------------------------------------
1 | # performance
2 | ## Standard
3 | - Test simple of function return error: https://opendev.hashnode.dev/golang-test-performance-function-standard-1
4 | - comparing 2 function:
5 | ```go
6 | func newErr() error {
7 | return errors.new("this is error")
8 | }
9 | func fmtErr() error {
10 | return fmt.Errorf("this is error")
11 | }
12 | ```
13 | - Test convert string to int of 3 function: https://opendev.hashnode.dev/golang-test-performance-function-standard-1
14 | - comparing 3 function:
15 | - comparing 2 function:
16 | ```go
17 | func MethodInt(i int) string {
18 | return strconv.FormatInt(int64(i), 10)
19 | }
20 | func MethodItoa(i int) string {
21 | return strconv.Itoa(i)
22 | }
23 | func MethodFmt(i int) string {
24 | return fmt.Sprintf("%d", i)
25 | }
26 | ```
--------------------------------------------------------------------------------
/performances/standard/condition_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strings"
5 | "testing"
6 | )
7 |
8 | func CheckIfElseEmpty(s string) string {
9 | if s == "sdfsdsdfsdsdfsdsdfsdsdfsdsdfsd" {
10 | return s
11 | }
12 | return s
13 | }
14 | func CheckIfElseLen(s string) string {
15 | if len(s) == 30 {
16 | return s
17 | }
18 | return s
19 | }
20 |
21 | func CheckIfElseEqual(s string) string {
22 | if strings.EqualFold(s, "sdfsdsdfsdsdfsdsdfsdsdfsdsdfsd") {
23 | return s
24 | }
25 | return s
26 | }
27 |
28 | func BenchmarkIfElseEmpty(b *testing.B) {
29 | for i := 0; i < b.N; i++ {
30 | // TODO: Your Code Here
31 | CheckIfElseEmpty("sdfsdsdfsdsdfsdsdfsdsdfsdsdfsd")
32 | }
33 | }
34 |
35 | func BenchmarkIfElseEqual(b *testing.B) {
36 | for i := 0; i < b.N; i++ {
37 | // TODO: Your Code Here
38 | CheckIfElseEqual("sdfsdsdfsdsdfsdsdfsdsdfsdsdfsd")
39 | }
40 | }
41 | func BenchmarkIfElseLen(b *testing.B) {
42 | for i := 0; i < b.N; i++ {
43 | // TODO: Your Code Here
44 | CheckIfElseLen("anc")
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/performances/standard/convert.go:
--------------------------------------------------------------------------------
1 | package main
2 |
--------------------------------------------------------------------------------
/performances/standard/convert_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "testing"
7 | )
8 |
9 | func MethodInt(i int) string {
10 | return strconv.FormatInt(int64(i), 10)
11 | }
12 | func MethodItoa(i int) string {
13 | return strconv.Itoa(i)
14 | }
15 | func MethodFmt(i int) string {
16 | return fmt.Sprintf("%d", i)
17 | }
18 | func BenchmarkFmt(b *testing.B) {
19 | // TODO: Initialize
20 | number := 10
21 | for i := 0; i < b.N; i++ {
22 | // TODO: Your Code Here
23 | MethodFmt(number)
24 | }
25 | }
26 |
27 | func BenchmarkMethodInt(b *testing.B) {
28 | // TODO: Initialize
29 | number := 10
30 | for i := 0; i < b.N; i++ {
31 | // TODO: Your Code Here
32 | MethodInt(number)
33 | }
34 | }
35 | func BenchmarkMethodItoa(b *testing.B) {
36 | // TODO: Initialize
37 | number := 10
38 | for i := 0; i < b.N; i++ {
39 | // TODO: Your Code Here
40 | MethodItoa(number)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/redis/cluster/7000/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/7001/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/7002/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/7003/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/7004/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/7005/redis.conf:
--------------------------------------------------------------------------------
1 | port 7000
2 | cluster-enabled yes
3 | cluster-config-file nodes.conf
4 | cluster-node-timeout 5000
5 | appendonly yes
6 | bind 0.0.0.0
--------------------------------------------------------------------------------
/redis/cluster/README.md:
--------------------------------------------------------------------------------
1 | # redis cluster
2 |
3 | docker run -d -it -v `pwd`/7000:/redis --name node-1 -p 6380:7000 --network redis-cluster redis redis-server /redis/redis.conf
4 | docker run -d -it -v `pwd`/7001:/redis --name node-2 -p 6381:7000 --network redis-cluster redis redis-server /redis/redis.conf
5 | docker run -d -it -v `pwd`/7002:/redis --name node-3 -p 6382:7000 --network redis-cluster redis redis-server /redis/redis.conf
--------------------------------------------------------------------------------
/redis/custom-values.yaml:
--------------------------------------------------------------------------------
1 | master:
2 | password: "integration"
3 | resources:
4 | requests:
5 | memory: "1Gi"
6 | cpu: "500m" # 0.5 CPU
7 | limits:
8 | cpu: "1000m"
9 | memory: "2Gi"
10 | persistence:
11 | enabled: true
12 |
13 | pdb:
14 | create: true
15 | minAvailable: 1
16 | maxUnavailable: ""
17 |
18 | architecture: standalone
19 |
20 | metrics:
21 | enabled: true
22 | service:
23 | type: LoadBalancer
--------------------------------------------------------------------------------
/redis/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "open-dev/redis/redisPkg"
7 | "time"
8 | )
9 |
10 | func main() {
11 | ctx := context.Background()
12 | fmt.Println("")
13 | redis := redisPkg.InitRedis()
14 | fmt.Println(redis)
15 | err := redis.Set(ctx, "demo-key-123", "", time.Duration(time.Second)*2).Err()
16 | fmt.Println(err)
17 | }
18 |
--------------------------------------------------------------------------------
/redis/network.yaml:
--------------------------------------------------------------------------------
1 | # allow all traffic
2 | apiVersion: networking.k8s.io/v1
3 | kind: NetworkPolicy
4 | metadata:
5 | name: allow-all-egress
6 | spec:
7 | podSelector: {}
8 | egress:
9 | - {}
10 | ingress:
11 | - {}
12 | policyTypes:
13 | - Ingress
14 | - Egress
15 |
16 | # Allow all egress traffic
17 | # apiVersion: networking.k8s.io/v1
18 | # kind: NetworkPolicy
19 | # metadata:
20 | # name: allow-all-egress
21 | # spec:
22 | # podSelector: {}
23 | # egress:
24 | # - {}
25 | # policyTypes:
26 | # - Egress
27 |
28 | # Allow all ingress traffic
29 | # apiVersion: networking.k8s.io/v1
30 | # kind: NetworkPolicy
31 | # metadata:
32 | # name: allow-all-ingress
33 | # spec:
34 | # podSelector: {}
35 | # ingress:
36 | # - {}
37 | # policyTypes:
38 | # - Ingress
39 |
40 | # ---
41 | # apiVersion: networking.k8s.io/v1
42 | # kind: NetworkPolicy
43 | # metadata:
44 | # name: default-deny-egress
45 | # spec:
46 | # podSelector: {}
47 | # policyTypes:
48 | # - Egress
--------------------------------------------------------------------------------
/redis/pipeline/README.md:
--------------------------------------------------------------------------------
1 | # pipeline
2 |
3 | ## redis ZRANGE:
4 | ### usecase:
5 | - requirement: handle logic attempt access for period
6 | ### implement
7 | - document: https://redis.io/commands/zadd/
8 | - code example: https://github.com/ducnpdev/open-dev/blob/master/redis/pipeline/range.go
9 |
10 | ### benchmark
11 | - execute only one
12 | ```
13 | go test -bench=.
14 | ```
15 | - execute with count
16 | ```
17 | go test -bench=. -count 5
18 | ```
19 | - output:
20 | ```
21 | goos: darwin
22 | goarch: arm64
23 | pkg: open-dev/redis/pipeline
24 | BenchmarkPrimeNumbers-8 1303 848796 ns/op
25 | BenchmarkPrimeNumbers-8 1336 850908 ns/op
26 | BenchmarkPrimeNumbers-8 1425 812590 ns/op
27 | PASS
28 | ok open-dev/redis/pipeline 5.469s
29 | ```
--------------------------------------------------------------------------------
/redis/pipeline/range_test.go:
--------------------------------------------------------------------------------
1 | package pipeline
2 |
3 | import (
4 | "context"
5 | "testing"
6 | )
7 |
8 | func BenchmarkPrimeNumbers(b *testing.B) {
9 | ctx := context.Background()
10 | pline := pipeline()
11 | for i := 0; i < b.N; i++ {
12 | checkattempt(ctx, pline)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/redis/pubsub/pub/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "log"
6 | "time"
7 |
8 | "github.com/go-redis/redis/v8"
9 | "github.com/google/uuid"
10 | )
11 |
12 | func main() {
13 | client := redis.NewClient(&redis.Options{
14 | Addr: "localhost:6379", // Địa chỉ Redis server
15 | })
16 | err := client.Ping(context.TODO()).Err()
17 | if err != nil {
18 | panic(err)
19 | }
20 | for i := 0; i < 1000; i++ {
21 | msg := uuid.New().String()
22 | err = client.Publish(context.TODO(), "opendev-channel", msg).Err()
23 | if err != nil {
24 | panic(err)
25 | }
26 | log.Println("Message published!", msg)
27 | time.Sleep(time.Second)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/redis/pubsub/sub/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "log"
6 |
7 | "github.com/go-redis/redis/v8"
8 | )
9 |
10 | func main() {
11 | client := redis.NewClient(&redis.Options{
12 | Addr: "localhost:6379",
13 | })
14 | err := client.Ping(context.TODO()).Err()
15 | if err != nil {
16 | panic(err)
17 | }
18 | // Đăng ký nhận thông báo từ channel "mychannel"
19 | pubsub := client.Subscribe(context.TODO(), "opendev-channel")
20 |
21 | // Nhận thông báo đầu tiên
22 | for {
23 | msg, err := pubsub.ReceiveMessage(context.TODO())
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 | log.Printf("Received message from channel: %s", msg.Payload)
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/redis/queue/consumer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 |
8 | "github.com/go-redis/redis/v8"
9 | )
10 |
11 | func main() {
12 |
13 | ctx := context.TODO()
14 |
15 | redisClient := redis.NewClient(&redis.Options{
16 | Addr: "localhost:6379",
17 | Password: "",
18 | DB: 0,
19 | })
20 |
21 | for {
22 |
23 | result, err := redisClient.BLPop(ctx, 0*time.Second, "payments").Result()
24 |
25 | if err != nil {
26 | fmt.Println(err.Error())
27 | } else {
28 | for item := range result {
29 | str := result[item]
30 | fmt.Println(str)
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/redis/queue/producer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "net/http"
8 |
9 | "github.com/go-redis/redis/v8"
10 | )
11 |
12 | func main() {
13 | http.HandleFunc("/payments", paymentsHandler)
14 | http.ListenAndServe(":8080", nil)
15 | }
16 |
17 | func paymentsHandler(w http.ResponseWriter, req *http.Request) {
18 |
19 | redisClient := redis.NewClient(&redis.Options{
20 | Addr: "localhost:6379",
21 | Password: "",
22 | DB: 0,
23 | })
24 |
25 | ctx := context.TODO()
26 |
27 | buf := new(bytes.Buffer)
28 |
29 | // Include a Validation logic here to sanitize the req.Body when working in a production environment
30 |
31 | buf.ReadFrom(req.Body)
32 |
33 | paymentDetails := buf.String()
34 |
35 | err := redisClient.RPush(ctx, "payments", paymentDetails).Err()
36 |
37 | if err != nil {
38 | fmt.Fprintf(w, err.Error()+"\r\n")
39 | return
40 | }
41 | fmt.Fprintf(w, "Payment details accepted successfully\r\n")
42 | }
43 |
--------------------------------------------------------------------------------
/redis/redisPkg/connect.go:
--------------------------------------------------------------------------------
1 | package redisPkg
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/go-redis/redis/v8"
7 | )
8 |
9 | // var RedisIn *redis.Client
10 |
11 | func InitRedis() *redis.Client {
12 | rdb := redis.NewClient(&redis.Options{
13 | Addr: "localhost:6379",
14 | Password: "", // no password set
15 | DB: 0, // use default DB
16 | })
17 |
18 | err := rdb.Ping(context.Background()).Err()
19 | if err != nil {
20 | panic(err)
21 | }
22 |
23 | return rdb
24 | }
25 |
--------------------------------------------------------------------------------
/redis/test.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/redis/test.txt
--------------------------------------------------------------------------------
/redis/test.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/redis/test.yaml
--------------------------------------------------------------------------------
/terraform/README.md:
--------------------------------------------------------------------------------
1 | # start project
2 | - step deploy
3 | ```tf
4 | terraform init
5 | terraform plan
6 | terraform apply
7 | ```
--------------------------------------------------------------------------------
/terraform/apps/.gitignore:
--------------------------------------------------------------------------------
1 | .terraform*
--------------------------------------------------------------------------------
/terraform/apps/apigw/README.md:
--------------------------------------------------------------------------------
1 | # terraform integration aws-apigw
--------------------------------------------------------------------------------
/terraform/apps/apigw/apikey.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_api_key" "tfAPIKey" {
2 | name = "tf-api-key"
3 | description = "terrafrom description"
4 | enabled = true
5 | value = "2af0b7bc-4375-4df2-a44d-2eff998a1193"
6 | }
7 |
8 | resource "aws_api_gateway_usage_plan_key" "tfUsagePlanKey" {
9 | key_id = aws_api_gateway_api_key.tfAPIKey.id
10 | key_type = "API_KEY"
11 | usage_plan_id = aws_api_gateway_usage_plan.tfUsagePlan.id
12 | }
--------------------------------------------------------------------------------
/terraform/apps/apigw/deployment.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_deployment" "tfdeployment" {
2 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
3 |
4 | # triggers = {
5 | # redeployment = sha1(jsonencode(aws_api_gateway_rest_api.tfapi.body))
6 | # }
7 |
8 | lifecycle {
9 | create_before_destroy = true
10 | }
11 | }
12 |
13 | # resource "aws_api_gateway_stage" "example" {
14 | # deployment_id = aws_api_gateway_deployment.example.id
15 | # rest_api_id = aws_api_gateway_rest_api.example.id
16 | # stage_name = "example"
17 | # }
18 |
--------------------------------------------------------------------------------
/terraform/apps/apigw/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.4.6"
3 | }
4 |
5 | provider "aws" {
6 | access_key = ""
7 | secret_key = ""
8 | region = var.aws_region
9 | token = ""
10 | endpoints {
11 | sts = ""
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/terraform/apps/apigw/resource.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_resource" "tfdms" {
2 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
3 | parent_id = aws_api_gateway_rest_api.tfapi.root_resource_id
4 | path_part = "dms"
5 | }
6 |
7 | resource "aws_api_gateway_resource" "tfdmsv1" {
8 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
9 | parent_id = aws_api_gateway_resource.tfdms.id
10 | path_part = "v1"
11 | }
12 |
13 | resource "aws_api_gateway_resource" "tfdmsv1vendor" {
14 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
15 | parent_id = aws_api_gateway_resource.tfdmsv1.id
16 | path_part = "vendor"
17 | }
18 |
19 | resource "aws_api_gateway_resource" "tfdmsv1vendorlogin" {
20 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
21 | parent_id = aws_api_gateway_resource.tfdmsv1vendor.id
22 | path_part = "login"
23 | }
24 |
--------------------------------------------------------------------------------
/terraform/apps/apigw/stage.tf:
--------------------------------------------------------------------------------
1 | #
2 | # Stage and Stage Settings
3 | #
4 |
5 | resource "aws_api_gateway_stage" "dev" {
6 | deployment_id = aws_api_gateway_deployment.tfdeployment.id
7 | rest_api_id = aws_api_gateway_rest_api.tfapi.id
8 | stage_name = "dev"
9 | }
10 |
11 | #resource "aws_api_gateway_stage" "uat" {
12 | # deployment_id = aws_api_gateway_deployment.example.id
13 | # rest_api_id = aws_api_gateway_rest_api.tfapi.id
14 | # stage_name = "uat"
15 | #}
16 |
17 | # resource "aws_api_gateway_stage" "prod" {
18 | # deployment_id = aws_api_gateway_deployment.example.id
19 | # rest_api_id = aws_api_gateway_rest_api.example.id
20 | # stage_name = "prod"
21 | #}
22 |
23 |
24 |
25 |
26 | # resource "aws_api_gateway_method_settings" "example" {
27 | # rest_api_id = aws_api_gateway_rest_api.example.id
28 | # stage_name = aws_api_gateway_stage.example.stage_name
29 | # method_path = "*/*"
30 |
31 | # settings {
32 | # metrics_enabled = true
33 | # }
34 | # }
--------------------------------------------------------------------------------
/terraform/apps/apigw/usageplan.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_usage_plan" "tfUsagePlan" {
2 | name = "tf-my-usage-plan"
3 | description = "my description"
4 | product_code = "MYCODE"
5 |
6 | api_stages {
7 | api_id = aws_api_gateway_rest_api.tfapi.id
8 | stage = aws_api_gateway_stage.dev.stage_name
9 | }
10 |
11 | # api_stages {
12 | # api_id = aws_api_gateway_rest_api.example.id
13 | # stage = aws_api_gateway_stage.production.stage_name
14 | # }
15 |
16 | quota_settings {
17 | limit = 20
18 | # offset = 2
19 | period = "DAY" // WEEK
20 | }
21 |
22 | throttle_settings {
23 | burst_limit = 5
24 | rate_limit = 10
25 | }
26 | }
--------------------------------------------------------------------------------
/terraform/apps/apigw/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | default = "ap-southeast-1"
3 | description = "AWS Region to deploy example API Gateway REST API"
4 | type = string
5 | }
6 | variable "rest_api_name" {
7 | default = "tf-study-api-gateway-rest-api"
8 | description = "Name of the API Gateway REST API (can be used to trigger redeployments)"
9 | type = string
10 | }
11 |
12 | variable "rest_api_path" {
13 | default = "/path1"
14 | description = "Path to create in the API Gateway REST API (can be used to trigger redeployments)"
15 | type = string
16 | }
17 |
18 | variable "rest_api_path_dms" {
19 | default = "/dms/v1/vendor/login"
20 | description = "Path to create in the API Gateway REST API (can be used to trigger redeployments)"
21 | type = string
22 | }
23 |
24 | variable "rest_api_path_dms_1" {
25 | default = "/dms/v1/file/create"
26 | description = "Path to create in the API Gateway REST API (can be used to trigger redeployments)"
27 | type = string
28 | }
29 |
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/apikey.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_api_key" "ekyc_service" {
2 | name = var.api_key_name
3 | description = "ekyc service"
4 | enabled = true
5 | value = var.api_key_value
6 | }
7 |
8 | resource "aws_api_gateway_usage_plan_key" "ekyc_service_key" {
9 | key_id = aws_api_gateway_api_key.ekyc_service.id
10 | key_type = "API_KEY"
11 | usage_plan_id = aws_api_gateway_usage_plan.ekyc_service.id
12 | }
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/integration.tf:
--------------------------------------------------------------------------------
1 |
2 | ## vpc-link integration
3 | resource "aws_api_gateway_integration" "ekyc_service_integration_nlb" {
4 | rest_api_id = var.apigw_id
5 | resource_id = aws_api_gateway_resource.ekyc_dev_v1_get_image.id
6 | http_method = aws_api_gateway_method.get_image.http_method
7 | integration_http_method = "POST"
8 | type = "HTTP"
9 | uri = var.vpc_link_url
10 | connection_type = "VPC_LINK"
11 | connection_id = var.vpc_link_id
12 | }
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.4.6"
3 | }
4 |
5 | provider "aws" {
6 | region = var.aws_region
7 | profile = var.profile
8 | token = ""
9 | endpoints {
10 | sts = ""
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/method.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_method" "get_image" {
2 | rest_api_id = var.apigw_id
3 | resource_id = aws_api_gateway_resource.ekyc_dev_v1_get_image.id
4 | http_method = "POST"
5 |
6 | authorization = "NONE"
7 | api_key_required = true
8 | request_parameters = {
9 | "method.request.header.x-api-key" = true
10 | }
11 | }
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/resource.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_resource" "ekyc_dev" {
2 | rest_api_id = var.apigw_id
3 | parent_id = var.apigw_root_resource
4 | path_part = "ekycservice"
5 | }
6 |
7 | resource "aws_api_gateway_resource" "ekyc_dev_v1" {
8 | rest_api_id = var.apigw_id
9 | parent_id = aws_api_gateway_resource.ekyc_dev.id
10 | path_part = "v1"
11 | }
12 |
13 | resource "aws_api_gateway_resource" "ekyc_dev_v1_get_image" {
14 | rest_api_id = var.apigw_id
15 | parent_id = aws_api_gateway_resource.ekyc_dev_v1.id
16 | path_part = "get-images"
17 | }
18 |
--------------------------------------------------------------------------------
/terraform/apps/apigw_thien/usageplan.tf:
--------------------------------------------------------------------------------
1 | resource "aws_api_gateway_usage_plan" "ekyc_service" {
2 | name = "ekyc_service"
3 | description = ""
4 | product_code = ""
5 |
6 | api_stages {
7 | api_id = var.apigw_id
8 | stage = var.apigw_stage
9 | throttle {
10 | path = var.throttle_method_path_image_get
11 | burst_limit = 3
12 | rate_limit = 6
13 | }
14 | }
15 |
16 | quota_settings {
17 | limit = 10000
18 | # offset = 2
19 | period = "DAY" // WEEK
20 | }
21 |
22 | throttle_settings {
23 | burst_limit = 5
24 | rate_limit = 10
25 | }
26 |
27 |
28 |
29 | }
--------------------------------------------------------------------------------
/terraform/apps/lambda/main.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/terraform/apps/lambda/main.tf
--------------------------------------------------------------------------------
/terraform/apps/sqs/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.4.6"
3 | }
4 |
5 | provider "aws" {
6 | access_key = ""
7 | secret_key = ""
8 | region = var.aws_region
9 | token = ""
10 | endpoints {
11 | sts = ""
12 | }
13 | }
--------------------------------------------------------------------------------
/terraform/apps/sqs/queuefifo.tf:
--------------------------------------------------------------------------------
1 | resource "aws_sqs_queue" "terraform_queue" {
2 | name = var.sqs_hdss_name
3 | fifo_queue = true
4 | content_based_deduplication = true
5 | visibility_timeout_seconds = 120
6 | message_retention_seconds = 432000
7 | }
--------------------------------------------------------------------------------
/terraform/apps/sqs/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | default = "ap-southeast-1"
3 | description = "AWS Region to deploy sqs"
4 | type = string
5 | }
6 | variable "sqs_hdss_name" {
7 | default = "queue_name.fifo"
8 | description = "sqs name"
9 | type = string
10 | }
11 |
--------------------------------------------------------------------------------
/terraform/apps/ssm/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.4.6"
3 | }
4 |
5 | provider "aws" {
6 | access_key = ""
7 | secret_key = ""
8 | region = var.aws_region
9 | }
--------------------------------------------------------------------------------
/terraform/apps/ssm/paramter.tf:
--------------------------------------------------------------------------------
1 | resource "aws_ssm_parameter" "parameter_name" {
2 | name = var.parameter_name_key
3 | type = "String"
4 | value = "{\"secretKey\":\"123\",\"url\":\"https://google.com\",\"secretKeyExternal\":\"\",\"headers\":{\"key\":\"9Buvd48nJsMHe\",\"x-api-key\":\"9Buvd48p5p2HJsMHe\",\"Content-Type\":\"application/json\"}}"
5 | }
--------------------------------------------------------------------------------
/terraform/apps/ssm/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | default = "ap-southeast-1"
3 | description = "AWS Region to deploy parameter"
4 | type = string
5 | }
6 |
7 | variable "parameter_name_key" {
8 | default = "sm-parameter-apse1-lab-name"
9 | description = "paramter store of name"
10 | type = string
11 | }
12 |
--------------------------------------------------------------------------------
/terraform/apps/vpc/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.4.6"
3 | }
4 |
5 | provider "aws" {
6 | access_key = ""
7 | secret_key = ""
8 | region = var.aws_region
9 | }
10 |
--------------------------------------------------------------------------------
/terraform/apps/vpc/subnet.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/terraform/apps/vpc/subnet.tf
--------------------------------------------------------------------------------
/terraform/apps/vpc/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | default = "ap-southeast-1"
3 | description = "AWS Region to deploy example API Gateway REST API"
4 | type = string
5 | }
6 |
--------------------------------------------------------------------------------
/terraform/apps/vpc/vpc.tf:
--------------------------------------------------------------------------------
1 | resource "aws_lb" "example" {
2 | name = "example"
3 | internal = true
4 | load_balancer_type = "network"
5 |
6 | subnet_mapping {
7 | subnet_id = "subnet-0f622c64f995415d9"
8 | }
9 | }
10 |
11 | resource "aws_api_gateway_vpc_link" "tfvpclink" {
12 | name = "tfvpclink"
13 | description = "terraform create vpc link"
14 | target_arns = [aws_lb.example.arn]
15 | }
16 |
17 | # resource "aws_default_vpc" "default" {
18 | # tags = {
19 | # Name = "Default VPC"
20 | # }
21 | # }
22 | # resource "aws_subnet" "main" {
23 | # vpc_id = aws_default_vpc.default.id
24 | # # cidr_block = "172.31.0.0/16"
25 |
26 | # tags = {
27 | # Name = "Main"
28 | # }
29 | # }
--------------------------------------------------------------------------------
/tls/base64parse/certificate_base64.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/tls/base64parse/certificate_base64.txt
--------------------------------------------------------------------------------
/tls/base64parse/file.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDePevzoudwdl2n
3 | j1T99lUoaFa3QckMBYin4zJhFCZ65Xyg6fKUyahglznOXknlmwm3qyFY2fL2Cug+
4 | 4wxyFocTMllMY5H4279ofAS+DuKP9DWL75EbakoPUhebbt4pBlv1OxuYjlHq17f0
5 | wv8PXlw4Zul7mwtl4HemwYmAhSgSiddE72ApF4cD6Wpulryyy2p0FQIIRHpBJae0
6 | 5ubpwgdgT*****wtmWykYeeP5AoGBAMNI
7 | Ae9N4WygEJrfdVzKSvZcyOuNoN5B3YQnvkPb1eoSP3IlfpyO9P1TFrFKlu4rVCgg
8 | RAKlgFl25gl87Xfv0gXZdycImIS2XDmb2voefpG/f88kwqpbSf67VuwmXg3yDclK
9 | yZTBTpTgyv4bXcbXWlMIwpbybGhEkfchcexyPKQxAoGBAKVqPZmWHty4Tz7d0KYK
10 | BzkdOQf5sZb88u1mrIFli4fLQVnQMeHAnwrEfBsl+NSmLmLpicURUYTsX8wUzJ+n
11 | 7ZpbxwZ2qnYYoC9DhwTq7/KaioKncMzlXALZBg1pExUJwhGaVB711cXfRyeW+Ngo
12 | k849ma89xEZNX0meoINPZ73m
13 | -----END PRIVATE KEY-----
14 |
--------------------------------------------------------------------------------
/tls/base64parse/file.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEgzCCAmsCAQEwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVk4xDDAKBgNV
3 | BAgMA0hDTTERMA8GA1UEBwwIUGh1Tmh1YW4xDDAKBgNVBAoMA0hEQjELMAkGA1UE
4 | CwwCSVQxDDAKBgNVBAMMA0FQSTEjMCEGCSqGSIb3DQEJARYUaGRiYXBpQGhkYmFu
5 | ay5jb20udm4wHhcNZDUtb9G+Cj4cEWzGgtd4bWDwH
6 | mDSMIfaWWyxRJ7vj4Qvfqx31QjD1xpCegc3l6saeHFNy93LSvJOHO2s1w0WIOtAc
7 | 3u+fruKhRMTgPEgetZVrrqRxuq/G/heHN08H7iRsHjG0cRAHK2daCqNhfx+bZi7z
8 | bUll2H4gYqt/LGYy+MtJlr4FqnQZkS6UdXpBJgGT91JhhKfv8cwGhsobmoSbTVn+
9 | N+p0Yrz5YtMN48VUqfsz/4CRuseERv1orDszzohqq96jpqYqlFxcguj8twApgCMJ
10 | XwQya13vyTrfTPkAJRz9hSS1tMTUJKVfQIAufb18ft8YOWbdSbNY3LqirDuDqIiu
11 | mXm+K4CMAUFAgxrT2TJC+cua6PQA+OU9t9stA/GuuKf6n3hNum84eaGtfhq1ET3g
12 | RDmPTXuPDTMAhb10txhpOOa7Qz81ZgpkgUirI9Jh+CyvuTtczCfJ20wdsr3KHgoN
13 | uz9CpOvlyg==
14 | -----END CERTIFICATE-----
15 |
--------------------------------------------------------------------------------
/usecase/blake/2b.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "golang.org/x/crypto/blake2b"
5 | )
6 |
7 | // NewBlake2b256 ...
8 | func NewBlake2b256(data []byte) []byte {
9 | hash := blake2b.Sum256(data)
10 | return hash[:]
11 | }
12 |
13 | // NewBlake2b512 ...
14 | func NewBlake2b512(data []byte) []byte {
15 | hash := blake2b.Sum512(data)
16 | return hash[:]
17 | }
18 |
--------------------------------------------------------------------------------
/usecase/blake/2s.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // // NewBlake2b128 ...
4 | // func NewBlake2s128(data []byte) []byte {
5 | // hash, _ := blake2s.New128(data)
6 | // return hash.Sum(nil)
7 | // }
8 |
--------------------------------------------------------------------------------
/usecase/blake/2s_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func TestNewBlake2s128(t *testing.T) {
10 | for i, tt := range []struct {
11 | in []byte
12 | out string
13 | }{
14 | {[]byte(""), "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8"},
15 | {[]byte("abc"), "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"},
16 | {[]byte("hello"), "324dcf027dd4a30a932c441f365a25e86b173defa4b8e58948253471b81b72cf"},
17 | } {
18 | t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
19 | result := NewBlake2s128(tt.in)
20 | if hex.EncodeToString(result) != tt.out {
21 | t.Errorf("want %v; got %v", tt.out, hex.EncodeToString(result))
22 | }
23 | })
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/usecase/blake/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 |
7 | "golang.org/x/crypto/blake2s"
8 | )
9 |
10 | func main() {
11 | out := NewBlake2s128([]byte("abc"))
12 | fmt.Println(hex.EncodeToString(out))
13 | }
14 |
15 | // NewBlake2b128 ...
16 | func NewBlake2s128(data []byte) []byte {
17 | hash, _ := blake2s.New128(data)
18 | return hash.Sum(nil)
19 | }
20 |
--------------------------------------------------------------------------------
/usecase/context/cancel.go:
--------------------------------------------------------------------------------
1 | package main
2 |
--------------------------------------------------------------------------------
/usecase/context/deadline.go:
--------------------------------------------------------------------------------
1 | package main
2 |
--------------------------------------------------------------------------------
/usecase/context/package.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "sync"
4 |
5 | func main() {
6 | var wg sync.WaitGroup
7 | done := make(chan interface{})
8 | defer close(done)
9 |
10 | wg.Add(1)
11 | go func() {
12 | defer wg.Done()
13 | }()
14 |
15 | wg.Add(1)
16 | go func() {
17 | defer wg.Done()
18 | }()
19 |
20 | wg.Wait()
21 | }
22 |
--------------------------------------------------------------------------------
/usecase/context/timeout.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 | )
8 |
9 | func TimeOut() {
10 | ctx := context.Background()
11 | ctx, cancel := context.WithTimeout(ctx, time.Duration(time.Second)*2)
12 | defer cancel()
13 | var (
14 | value string
15 | )
16 | go func() {
17 | value = handle(ctx)
18 | }()
19 | select {
20 | case <-ctx.Done():
21 | fmt.Println(ctx.Err())
22 | fmt.Println("cancelling...")
23 | return
24 | }
25 | fmt.Println("value:", value)
26 | }
27 |
28 | func handle(ctx context.Context) string {
29 | for i := 0; i < 3; i++ {
30 | fmt.Println(i)
31 | }
32 | return "ok"
33 | }
34 |
--------------------------------------------------------------------------------
/usecase/crypto-demo/README.md:
--------------------------------------------------------------------------------
1 | # demo crypto
2 | - use algorith basic and most commonly
3 | ## code example:
4 | - sha1:
5 | ```go
6 | func NewSha1(data []byte) []byte {
7 | s := sha1.New()
8 | s.Write(data)
9 | return s.Sum(nil)
10 | }
11 | ```
12 | - sha256
13 | ```go
14 | func NewSha256(data []byte) []byte {
15 | s := sha256.New()
16 | s.Write(data)
17 | return s.Sum(nil)
18 | }
19 | ```
20 | - md5
21 | ```go
22 | func Md5test(str string) []byte {
23 | h := md5.New()
24 | io.WriteString(h, str)
25 | return h.Sum(nil)
26 | }
27 | ```
28 | - blake
29 | ```go
30 | // NewBlake2s128 ...
31 | func NewBlake2s128(data []byte) []byte {
32 | hash, _ := blake2s.New128(data)
33 | return hash.Sum(nil)
34 | }
35 |
36 | // NewBlake2s128 ...
37 | func NewBlake2s256(data []byte) []byte {
38 | hash, _ := blake2s.New256(data)
39 | return hash.Sum(nil)
40 | }
41 | // NewBlake2b256 ...
42 | func NewBlake2b256(data []byte) []byte {
43 | hash := blake2b.Sum256(data)
44 | return hash[:]
45 | }
46 |
47 | // NewBlake2b512 ...
48 | func NewBlake2b512(data []byte) []byte {
49 | hash := blake2b.Sum512(data)
50 | return hash[:]
51 | }
52 | ```
--------------------------------------------------------------------------------
/usecase/crypto-demo/blake/2b.go:
--------------------------------------------------------------------------------
1 | package cryptodemo
2 |
3 | import (
4 | "golang.org/x/crypto/blake2b"
5 | )
6 |
7 | // NewBlake2b256 ...
8 | func NewBlake2b256(data []byte) []byte {
9 | hash := blake2b.Sum256(data)
10 | return hash[:]
11 | }
12 |
13 | // NewBlake2b512 ...
14 | func NewBlake2b512(data []byte) []byte {
15 | hash := blake2b.Sum512(data)
16 | return hash[:]
17 | }
18 |
--------------------------------------------------------------------------------
/usecase/crypto-demo/blake/2s.go:
--------------------------------------------------------------------------------
1 | package cryptodemo
2 |
3 | import "golang.org/x/crypto/blake2s"
4 |
5 | // NewBlake2s128 ...
6 | func NewBlake2s128(data []byte) []byte {
7 | hash, _ := blake2s.New128(data)
8 | return hash.Sum(nil)
9 | }
10 |
11 | // NewBlake2s128 ...
12 | func NewBlake2s256(data []byte) []byte {
13 | hash, _ := blake2s.New256(data)
14 | return hash.Sum(nil)
15 | }
16 |
--------------------------------------------------------------------------------
/usecase/crypto-demo/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 | cryptodemo "open-dev/usecase/crypto-demo/blake"
7 | cryptodemomd5 "open-dev/usecase/crypto-demo/md5"
8 | cryptodemosha "open-dev/usecase/crypto-demo/sha"
9 | )
10 |
11 | func main() {
12 | str := "abc"
13 | fmt.Println("md5:", hex.EncodeToString(cryptodemomd5.Md5test(str)))
14 | fmt.Println("blake2s-128:", hex.EncodeToString(cryptodemo.NewBlake2s128([]byte(str))))
15 | fmt.Println("blake2s-256:", hex.EncodeToString(cryptodemo.NewBlake2s256([]byte(str))))
16 | fmt.Println("blake2b-256:", hex.EncodeToString(cryptodemo.NewBlake2b256([]byte(str))))
17 |
18 | fmt.Println("sha-1:", hex.EncodeToString(cryptodemosha.NewSha1([]byte(str))))
19 | fmt.Println("sha-256:", hex.EncodeToString(cryptodemosha.NewSha256([]byte(str))))
20 | }
21 |
--------------------------------------------------------------------------------
/usecase/crypto-demo/md5/md5.go:
--------------------------------------------------------------------------------
1 | package cryptodemo
2 |
3 | import (
4 | "crypto/md5"
5 | "io"
6 | )
7 |
8 | func Md5test(str string) []byte {
9 | h := md5.New()
10 | io.WriteString(h, str)
11 | return h.Sum(nil)
12 | }
13 |
--------------------------------------------------------------------------------
/usecase/crypto-demo/sha/sha1.go:
--------------------------------------------------------------------------------
1 | package cryptodemo
2 |
3 | import (
4 | "crypto/sha1"
5 | "crypto/sha256"
6 | )
7 |
8 | func NewSha1(data []byte) []byte {
9 | s := sha1.New()
10 | s.Write(data)
11 | return s.Sum(nil)
12 | }
13 |
14 | func NewSha256(data []byte) []byte {
15 | s := sha256.New()
16 | s.Write(data)
17 | return s.Sum(nil)
18 | }
19 |
--------------------------------------------------------------------------------
/usecase/defer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | type Person struct {
6 | Name string
7 | }
8 |
9 | // C1
10 | func main() {
11 | p := Person{}
12 | defer func() {
13 | fmt.Printf("name: %s \n", p.Name)
14 | }()
15 | p.Name = "Opendev"
16 | }
17 |
18 | // C2
19 | func main1() {
20 | p := Person{}
21 | defer fmt.Printf("name %s \n", p.Name)
22 | p.Name = "Opendev"
23 | }
24 |
--------------------------------------------------------------------------------
/usecase/environment/dev.yaml:
--------------------------------------------------------------------------------
1 | env_string: "value env string develop"
2 | env_number: 222
--------------------------------------------------------------------------------
/usecase/environment/prod.yaml:
--------------------------------------------------------------------------------
1 | env_string: "value env string production"
2 | env_number: 111
--------------------------------------------------------------------------------
/usecase/function/README.md:
--------------------------------------------------------------------------------
1 | # function
2 | ## variadic function
3 | ### khái niệm:
4 | - variadic function là một function mà cho phép truyền vào bất kì một số nào
5 | - trong golang, để có thể truyền variadic function ta có thể dùng `...`
6 | - xem ví dụ:
7 | ```go
8 | func total(numbers ...int) {
9 | fmt.Print(numbers, " ")
10 | total := 0
11 | for _, num := range numbers {
12 | total += num
13 | }
14 | fmt.Println(total)
15 | }
16 | ```
17 |
18 | ### calling:
19 | - để call func total ta dùng:
20 | ```
21 | total(1, 2, 3) => output: 6
22 | total(1) => output: 1
23 | ```
24 | - hoặc nếu bạn muốn truyền vào func một slice,
25 | ```
26 | numbers := []int{1, 2, 3, 4}
27 | total(numbers...)
28 | => output: 10
29 | ```
30 | - call variadic function với một tham số khác.
31 | ```
32 | func prNumber(sep string, numbers ...int) {
33 | for i, number := range numbers {
34 | if i > 0 {
35 | fmt.Print(sep)
36 | }
37 | fmt.Print(number)
38 | }
39 | }
40 | prNumber(",", 11, 22, 33)
41 | => output: 11,22,33
42 | ```
--------------------------------------------------------------------------------
/usecase/function/variadic.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func total(numbers ...int) {
6 | fmt.Print(numbers, " ")
7 | total := 0
8 | for _, num := range numbers {
9 | total += num
10 | }
11 | fmt.Println(total)
12 | }
13 |
14 | func main() {
15 | numbers := []int{1, 2, 3, 4}
16 | total(numbers...)
17 | total(1, 2, 3)
18 |
19 | prNumber(",", 11, 22, 33)
20 | }
21 |
22 | func prNumber(sep string, numbers ...int) {
23 | for i, number := range numbers {
24 | if i > 0 {
25 | fmt.Print(sep)
26 | }
27 | fmt.Print(number)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/usecase/images/resizeImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/images/resizeImage.png
--------------------------------------------------------------------------------
/usecase/json/README.md:
--------------------------------------------------------------------------------
1 | # golang read and write file json data
2 | ## read json
--------------------------------------------------------------------------------
/usecase/jwttoken/README.md:
--------------------------------------------------------------------------------
1 | # jwt
2 |
3 | ## parse token
4 | - input token data: eyJraWQ******o10SMU_Zw1un3Q
5 | - output:
6 | - header:
7 | ```json
8 | {
9 | "kid": "YuyXoY",
10 | "alg": "RS256"
11 | }
12 | ```
13 | - payload:
14 | ```json
15 | {
16 | "iss": "https://appleid.apple.com",
17 | "aud": "com.tn.vpn.test",
18 | "exp": 16****606,
19 | "iat": 16****06,
20 | "sub": "000830.b5269f****6b552f.0130",
21 | "nonce": "fb5753a43f4****e14ed875d",
22 | "c_hash": "84eg****EiQ",
23 | "email": "q****v@pr****ay.appleid.com",
24 | "email_verified": "true",
25 | "is_private_email": "true",
26 | "auth_time": 16****06,
27 | "nonce_supported": true
28 | }
29 | ```
30 | - code:
31 | ```go
32 | func ParserToken(tokenString string) {
33 | claims := jwt.MapClaims{}
34 | token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
35 | return []byte(""), nil
36 | })
37 | // ... error handling
38 | fmt.Println(token, err)
39 | // do something with decoded claims
40 | for key, val := range claims {
41 | fmt.Printf("Key: %v, value: %v\n", key, val)
42 | }
43 | }
44 | ```
--------------------------------------------------------------------------------
/usecase/jwttoken/parse.go:
--------------------------------------------------------------------------------
1 | package jwttoken
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/golang-jwt/jwt"
7 | )
8 |
9 | func ParserToken(tokenString string) {
10 | claims := jwt.MapClaims{}
11 | token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
12 | return []byte(""), nil
13 | })
14 | // ... error handling
15 | fmt.Println(token, err)
16 | // do something with decoded claims
17 | for key, val := range claims {
18 | fmt.Printf("Key: %v, value: %v\n", key, val)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/usecase/map/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/.DS_Store
--------------------------------------------------------------------------------
/usecase/map/p1/main_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestMap(t *testing.T) {
9 | cache := NewCache()
10 | for i := 0; i <= 100; i++ {
11 | // go func(i int) {
12 | cache.Set(fmt.Sprint(i), i)
13 | // }(i)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/usecase/map/p1/map_1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p1/map_1.1.png
--------------------------------------------------------------------------------
/usecase/map/p1/map_1.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p1/map_1.2.png
--------------------------------------------------------------------------------
/usecase/map/p2/main_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestMap(t *testing.T) {
9 | cache := NewCache()
10 | for i := 0; i <= 100; i++ {
11 | go func(i int) {
12 | cache.Set(fmt.Sprint(i), i)
13 | }(i)
14 | }
15 | }
16 |
17 | // go test ./... -v --race
18 |
--------------------------------------------------------------------------------
/usecase/map/p2/map_2.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p2/map_2.1.png
--------------------------------------------------------------------------------
/usecase/map/p2/map_2.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p2/map_2.2.png
--------------------------------------------------------------------------------
/usecase/map/p2/map_2.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p2/map_2.3.png
--------------------------------------------------------------------------------
/usecase/map/p3/main_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestMap(t *testing.T) {
9 | cache := NewCacheIndex(10)
10 | for i := 0; i <= 100; i++ {
11 | go func(i int) {
12 | cache.Set(fmt.Sprint(i), i)
13 | }(i)
14 | }
15 | }
16 |
17 | // go test ./... -v --race
18 |
--------------------------------------------------------------------------------
/usecase/map/p3/map_3.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p3/map_3.1.png
--------------------------------------------------------------------------------
/usecase/map/p3/map_3.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p3/map_3.2.png
--------------------------------------------------------------------------------
/usecase/map/p3/map_3.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p3/map_3.3.png
--------------------------------------------------------------------------------
/usecase/map/p3/map_3.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p3/map_3.4.png
--------------------------------------------------------------------------------
/usecase/map/p4/golang_map_4.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p4/golang_map_4.1.png
--------------------------------------------------------------------------------
/usecase/map/p4/golang_map_4.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p4/golang_map_4.2.png
--------------------------------------------------------------------------------
/usecase/map/p4/golang_map_4.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/map/p4/golang_map_4.3.png
--------------------------------------------------------------------------------
/usecase/password/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/rand"
5 | "fmt"
6 | "io"
7 | "math/big"
8 | )
9 |
10 | // Generate returns a newly generated password
11 | func Generate(minLength int, maxLength int) string {
12 | var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~")
13 |
14 | length, err := rand.Int(rand.Reader, big.NewInt(int64(maxLength-minLength)))
15 | if err != nil {
16 | panic(err) // handle this gracefully
17 | }
18 | length.Add(length, big.NewInt(int64(minLength)))
19 |
20 | intLength := int(length.Int64())
21 |
22 | newPassword := make([]byte, intLength)
23 | randomData := make([]byte, intLength+intLength/4)
24 | charLen := byte(len(chars))
25 | maxrb := byte(256 - (256 % len(chars)))
26 | i := 0
27 | for {
28 | if _, err := io.ReadFull(rand.Reader, randomData); err != nil {
29 | panic(err)
30 | }
31 | for _, c := range randomData {
32 | if c >= maxrb {
33 | continue
34 | }
35 | newPassword[i] = chars[c%charLen]
36 | i++
37 | if i == intLength {
38 | return string(newPassword)
39 | }
40 | }
41 | }
42 | }
43 |
44 | func main() {
45 | pw := Generate(10, 15)
46 | fmt.Printf("password: %s", pw)
47 | }
48 |
--------------------------------------------------------------------------------
/usecase/resizeImage.go:
--------------------------------------------------------------------------------
1 | package usecase
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "encoding/base64"
7 | "fmt"
8 | "image"
9 |
10 | "github.com/disintegration/imaging"
11 | )
12 |
13 | func ResizeImageFromBase64(imgBase64 string, newHeight int) (string, error) {
14 | // convert image is base64 to byte
15 | unbased, err := base64.StdEncoding.DecodeString(imgBase64)
16 | if err != nil {
17 | return "", fmt.Errorf("cannot decode base64 err=%v", err)
18 | }
19 |
20 | r := bytes.NewReader(unbased)
21 | // use library imaging
22 | // parse reader to image
23 | img, err := imaging.Decode(r)
24 | if err != nil {
25 | return "", err
26 | }
27 |
28 | // calculator new width of image
29 | newWidth := newHeight * img.Bounds().Max.X / img.Bounds().Max.Y
30 |
31 | // resize new image
32 | nrgba := imaging.Resize(img, newWidth, newHeight, imaging.Lanczos)
33 |
34 | return toBase64(nrgba)
35 | }
36 |
37 | func toBase64(dst *image.NRGBA) (string, error) {
38 | var b bytes.Buffer
39 | foo := bufio.NewWriter(&b)
40 | if err := imaging.Encode(foo, dst, imaging.JPEG); err != nil {
41 | return "", err
42 | }
43 | return base64.StdEncoding.EncodeToString(b.Bytes()), nil
44 | }
45 |
--------------------------------------------------------------------------------
/usecase/time/README.md:
--------------------------------------------------------------------------------
1 | ## debug resource
2 | - run: go tool pprof http://localhost:1234/debug/pprof/goroutine
3 | - run heap: go tool pprof http://localhost:1234/debug/pprof/heap
4 | - run allocs: go tool pprof http://localhost:1234/debug/pprof/allocs
5 | -
--------------------------------------------------------------------------------
/usecase/time/profile001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile001.png
--------------------------------------------------------------------------------
/usecase/time/profile002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile002.png
--------------------------------------------------------------------------------
/usecase/time/profile003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile003.png
--------------------------------------------------------------------------------
/usecase/time/profile004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile004.png
--------------------------------------------------------------------------------
/usecase/time/profile005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile005.png
--------------------------------------------------------------------------------
/usecase/time/profile006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile006.png
--------------------------------------------------------------------------------
/usecase/time/profile007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/profile007.png
--------------------------------------------------------------------------------
/usecase/time/tick.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | _ "net/http/pprof"
8 | "os"
9 | "os/signal"
10 | "syscall"
11 | "time"
12 | )
13 |
14 | type Event struct {
15 | }
16 |
17 | func handle(e Event) {
18 | fmt.Println(e)
19 | }
20 | func main() {
21 | go consumer(make(<-chan Event))
22 | // wait
23 | go func() {
24 | http.ListenAndServe(":1234", nil)
25 | }()
26 | sigs := make(chan os.Signal, 1)
27 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
28 | done := make(chan bool, 1)
29 | go func() {
30 | <-sigs
31 | done <- true
32 | }()
33 | <-done
34 | }
35 |
36 | // bad solution:
37 | func consumer(ch <-chan Event) {
38 | fmt.Println("start consumer")
39 | for {
40 | select {
41 | case event := <-ch:
42 | handle(event)
43 | case <-time.After(time.Nanosecond):
44 | log.Println("warning: no messages received")
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/usecase/time/tickHour.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickHour.png
--------------------------------------------------------------------------------
/usecase/time/tickNano-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickNano-2.png
--------------------------------------------------------------------------------
/usecase/time/tickNano-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickNano-3.png
--------------------------------------------------------------------------------
/usecase/time/tickNano-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickNano-4.png
--------------------------------------------------------------------------------
/usecase/time/tickNano.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickNano.png
--------------------------------------------------------------------------------
/usecase/time/tickSecond-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickSecond-2.png
--------------------------------------------------------------------------------
/usecase/time/tickSecond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ducnpdev/open-dev/7c4eb6a814bc54d33a6c02251129eeaed16b914a/usecase/time/tickSecond.png
--------------------------------------------------------------------------------