diff --git a/components/rpc/invoker/mosn/channel/xchannel.go b/components/rpc/invoker/mosn/channel/xchannel.go index 2c3b2fae20..f3891973d8 100644 --- a/components/rpc/invoker/mosn/channel/xchannel.go +++ b/components/rpc/invoker/mosn/channel/xchannel.go @@ -20,11 +20,15 @@ import ( "context" "errors" "fmt" + "io" "net" "sync" "sync/atomic" "time" + "mosn.io/pkg/buffer" + "mosn.io/pkg/log" + "mosn.io/api" common "mosn.io/layotto/components/pkg/common" @@ -93,8 +97,104 @@ type xChannel struct { pool *connPool } -// Do is handle RPCRequest to RPCResponse -func (m *xChannel) Do(req *rpc.RPCRequest) (*rpc.RPCResponse, error) { +// InvokeWithTargetAddress send request to specific provider address +func (m *xChannel) InvokeWithTargetAddress(req *rpc.RPCRequest) (*rpc.RPCResponse, error) { + // 1. context.WithTimeout + timeout := time.Duration(req.Timeout) * time.Millisecond + ctx, cancel := context.WithTimeout(req.Ctx, timeout) + defer cancel() + + // 2. get connection with specific address + conn, err := net.Dial("tcp", req.Header[rpc.TargetAddress][0]) + if err != nil { + return nil, err + } + wc := &wrapConn{Conn: conn} + + // 3. encode request + frame := m.proto.ToFrame(req) + buf, encErr := m.proto.Encode(req.Ctx, frame) + if encErr != nil { + return nil, common.Error(common.InternalCode, encErr.Error()) + } + + callChan := make(chan call, 1) + // 4. set timeout + deadline, _ := ctx.Deadline() + if err := conn.SetWriteDeadline(deadline); err != nil { + return nil, common.Error(common.UnavailebleCode, err.Error()) + } + + // 5. read package + go func() { + var err error + defer func() { + if err != nil { + callChan <- call{err: err} + } + wc.Close() + }() + + wc.buf = buffer.NewIoBuffer(defaultBufSize) + for { + // read data from connection + n, readErr := wc.buf.ReadOnce(conn) + if readErr != nil { + err = readErr + if readErr == io.EOF { + log.DefaultLogger.Debugf("[runtime][rpc]direct conn read-loop err: %s", readErr.Error()) + } else { + log.DefaultLogger.Errorf("[runtime][rpc]direct conn read-loop err: %s", readErr.Error()) + } + } + + if n > 0 { + iframe, decodeErr := m.proto.Decode(context.TODO(), wc.buf) + if decodeErr != nil { + err = decodeErr + log.DefaultLogger.Errorf("[runtime][rpc]direct conn decode frame err: %s", err) + break + } + frame, ok := iframe.(api.XRespFrame) + if frame == nil { + continue + } + if !ok { + err = errors.New("[runtime][rpc]xchannel type not XRespFrame") + log.DefaultLogger.Errorf("[runtime][rpc]direct conn decode frame err: %s", err) + break + } + callChan <- call{resp: frame} + return + + } + if err != nil { + break + } + if wc.buf != nil && wc.buf.Len() == 0 && wc.buf.Cap() > maxBufSize { + wc.buf.Free() + wc.buf.Alloc(defaultBufSize) + } + } + }() + + // 6. write packet + if _, err := conn.Write(buf.Bytes()); err != nil { + return nil, common.Error(common.UnavailebleCode, err.Error()) + } + + select { + case res := <-callChan: + if res.err != nil { + return nil, common.Error(common.UnavailebleCode, res.err.Error()) + } + return m.proto.FromFrame(res.resp) + case <-ctx.Done(): + return nil, common.Error(common.TimeoutCode, ErrTimeout.Error()) + } +} + +func (m *xChannel) Invoke(req *rpc.RPCRequest) (*rpc.RPCResponse, error) { // 1. context.WithTimeout timeout := time.Duration(req.Timeout) * time.Millisecond ctx, cancel := context.WithTimeout(req.Ctx, timeout) @@ -151,6 +251,14 @@ func (m *xChannel) Do(req *rpc.RPCRequest) (*rpc.RPCResponse, error) { } } +// Do is handle RPCRequest to RPCResponse +func (m *xChannel) Do(req *rpc.RPCRequest) (*rpc.RPCResponse, error) { + if _, ok := req.Header[rpc.TargetAddress]; ok && len(req.Header[rpc.TargetAddress]) > 0 { + return m.InvokeWithTargetAddress(req) + } + return m.Invoke(req) +} + // removeCall is delete xstate.calls by id func (m *xChannel) removeCall(xstate *xstate, id uint32) { xstate.mu.Lock() diff --git a/components/rpc/invoker/mosn/mosninvoker.go b/components/rpc/invoker/mosn/mosninvoker.go index 2917428ff6..7ef453b148 100644 --- a/components/rpc/invoker/mosn/mosninvoker.go +++ b/components/rpc/invoker/mosn/mosninvoker.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "strconv" // bridge to mosn _ "mosn.io/mosn/pkg/filter/network/proxy" @@ -93,7 +94,13 @@ func (m *mosnInvoker) Invoke(ctx context.Context, req *rpc.RPCRequest) (resp *rp // 1. validate request if req.Timeout == 0 { - req.Timeout = 3000 + req.Timeout = rpc.DefaultRequestTimeoutMs + if ts, ok := req.Header[rpc.RequestTimeoutMs]; ok && len(ts) > 0 { + t, err := strconv.Atoi(ts[0]) + if err == nil && t != 0 { + req.Timeout = int32(t) + } + } } req.Ctx = ctx log.DefaultLogger.Debugf("[runtime][rpc]request %+v", req) diff --git a/components/rpc/invoker/mosn/mosninvoker_test.go b/components/rpc/invoker/mosn/mosninvoker_test.go index 661aefb423..8d46ae9262 100644 --- a/components/rpc/invoker/mosn/mosninvoker_test.go +++ b/components/rpc/invoker/mosn/mosninvoker_test.go @@ -90,10 +90,27 @@ func Test_mosnInvoker_Invoke(t *testing.T) { Timeout: 100, Method: "Hello", Data: []byte("hello"), + Header: map[string][]string{}, } rsp, err := invoker.Invoke(context.Background(), req) assert.Nil(t, err) assert.Equal(t, "hello world!", string(rsp.Data)) + + req.Header[rpc.RequestTimeoutMs] = []string{"0"} + req.Timeout = 0 + rsp, err = invoker.Invoke(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, "hello world!", string(rsp.Data)) + + assert.Equal(t, int32(3000), req.Timeout) + + req.Header[rpc.RequestTimeoutMs] = []string{"100000"} + req.Timeout = 0 + rsp, err = invoker.Invoke(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, "hello world!", string(rsp.Data)) + + assert.Equal(t, int32(100000), req.Timeout) }) t.Run("panic", func(t *testing.T) { diff --git a/components/rpc/types.go b/components/rpc/types.go index 150b28fb23..95b95276ea 100644 --- a/components/rpc/types.go +++ b/components/rpc/types.go @@ -22,6 +22,15 @@ import ( "strings" ) +const ( + TargetAddress = "rpc_target_address" + RequestTimeoutMs = "rpc_request_timeout" +) + +const ( + DefaultRequestTimeoutMs = 3000 +) + // RPCHeader is storage header info type RPCHeader map[string][]string diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 47ad05e71b..353b163bf4 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -13,7 +13,9 @@ - Service Invocation - [Hello World](en/start/rpc/helloworld.md) - [Dubbo JSON RPC](en/start/rpc/dubbo_json_rpc.md) + - [Use OSS API](en/start/oss/start.md) - [API plugin: register your own API](en/start/api_plugin/helloworld.md) + - As the data plane of istio - [Integrate with istio 1.10.6](en/start/istio/) - [Integrate with istio 1.5.x](en/start/istio/start.md) diff --git a/docs/api/v1/s3.html b/docs/api/v1/s3.html index d56e57834c..4b17da38b6 100644 --- a/docs/api/v1/s3.html +++ b/docs/api/v1/s3.html @@ -515,7 +515,7 @@

oss.proto

Top

[gRPC Service] ObjectStorageService

-

ObjectStorageService

+

ObjectStorageService is an abstraction for blob storage or so called "object storage", such as alibaba cloud OSS, such as AWS S3.

You invoke ObjectStorageService API to do some CRUD operations on your binary file, e.g. query my file, delete my file, etc.

diff --git a/docs/en/api_reference/how_to_generate_api_doc.md b/docs/en/api_reference/how_to_generate_api_doc.md index cfe837c65e..36e419773a 100644 --- a/docs/en/api_reference/how_to_generate_api_doc.md +++ b/docs/en/api_reference/how_to_generate_api_doc.md @@ -1,4 +1,4 @@ -# How to generate `.pb.go` code and API reference +# How to generate `.pb.go` code and corresponding documentation Note: the commands below should be executed under layotto directory ```shell @@ -8,7 +8,10 @@ make proto Then you get: - `.pb.go` code - API reference docs -- updated sidebar in the doc site +- updated API reference list +- quickstart document (both chinese and english) +- updated sidebar (The tool will add the generated quickstart doc into the sidebar of https://mosn.io/layotto ) +- updated CI (The tool will add the generated quickstart doc into the CI script `etc/script/test-quickstart.sh`) That's all :) @@ -48,22 +51,8 @@ make proto.doc This command uses docker to run protoc-gen-doc and generate docs. ### **Use docker to run protoc-gen-doc** -`make proto.doc` essentially run commands below: +`make proto.doc` invokes the script `etc/script/generate-doc.sh`, which uses docker to run protoc-gen-doc. -``` -docker run --rm \ --v $(pwd)/docs/en/api_reference:/out \ --v $(pwd)/spec/proto/runtime/v1:/protos \ -pseudomuto/protoc-gen-doc --doc_opt=/protos/template.tmpl,runtime_v1.md runtime.proto -``` - -and - -```shell -docker run --rm \ --v $(pwd)/docs/en/api_reference:/out \ --v $(pwd)/spec/proto/runtime/v1:/protos \ -pseudomuto/protoc-gen-doc --doc_opt=/protos/template.tmpl,appcallback_v1.md appcallback.proto -``` +You can check `etc/script/generate-doc.sh` for more details. \ No newline at end of file diff --git a/docs/en/building_blocks/rpc/reference.md b/docs/en/building_blocks/rpc/reference.md index c91a9ce3ff..aed1cefaaa 100644 --- a/docs/en/building_blocks/rpc/reference.md +++ b/docs/en/building_blocks/rpc/reference.md @@ -4,7 +4,7 @@ Layotto's RPC API is based on [Mosn](https://mosn.io/en/)'s grpc handler, which The interface of the RPC API are consistent with [Dapr](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/), you could see its details in [invoke.go](https://github.com/mosn/layotto/blob/3802c4591181fdbcfb7dd07cbbdbadeaaada650a/sdk/go-sdk/client/invoke.go). -Using Layotto RPC invocation, your application can reliably and securely communicate with other applications using the standard HTTP or [X-Protocol](https://www.servicemesher.com/blog/x-protocol-common-address-solution/) protocols. +Using Layotto RPC invocation, your application can reliably and securely communicate with other applications using the standard HTTP or [X-Protocol](https://cloudnative.to/blog/x-protocol-common-address-solution/) protocols. ![sidecar](https://mosn.io/en/docs/concept/sidecar-pattern/sidecar-pattern.jpg) diff --git a/docs/en/design/notify/phone_call.md b/docs/en/design/notify/phone_call.md new file mode 100644 index 0000000000..5924ad8781 --- /dev/null +++ b/docs/en/design/notify/phone_call.md @@ -0,0 +1,71 @@ +# PhoneCall API design + +## What would you like to be added +IVR API, or PhoneCall API + +Developers can invoke this API to send voice messages to specific people. + +## Why is this needed +In the monitoring scenarios, monitor systems need to send alarm messages to people on-call. +The messages might be in different forms, including IM,SMS, Email and phone calls, depending on the level of urgency. + +## Product research +| IVR product |Docs| +|---|---| +|Aliyun VMS| https://www.aliyun.com/product/vms | +|AWS Pinpoint | https://aws.amazon.com/cn/pinpoint/ | + + +## Detailed Design + +We need to consider the following factors: +- Portability + For example, a monitor system might be deployed on alibaba cloud(using [VMS](https://www.aliyun.com/product/vms) to send voice message) or AWS (using [AWS Pinpoint](https://aws.amazon.com/cn/pinpoint/) to send voice message). So portability is important here. + +```proto +// PhoneCallService is one of Notify APIs. It's used to send voice messages +service PhoneCallService { + + // Send voice using the specific template + rpc SendVoiceWithTemplate(SendVoiceWithTemplateRequest) returns (SendVoiceWithTemplateResponse) {} + +} + +// The request of SendVoiceWithTemplate method +message SendVoiceWithTemplateRequest{ + + // If your system uses multiple IVR services at the same time, + // you can specify which service to use with this field. + string service_name = 1; + + // Required + VoiceTemplate template = 2; + + // Required + repeated string to_mobile = 3; + + // This field is required by some cloud providers. + string from_mobile = 4; + +} + +// VoiceTemplate +message VoiceTemplate{ + + // Required + string template_id = 1; + + // Required + map template_params = 2; + +} + +// The response of `SendVoiceWithTemplate` method +message SendVoiceWithTemplateResponse{ + + // Id of this request. + string request_id = 1; + +} + +``` diff --git a/docs/en/start/oss/start.md b/docs/en/start/oss/start.md new file mode 100644 index 0000000000..ee74618289 --- /dev/null +++ b/docs/en/start/oss/start.md @@ -0,0 +1,153 @@ + +# ObjectStorageService API demo + +This example shows how to invoke Layotto ObjectStorageService API. + +ObjectStorageService is an abstraction for blob storage or so called "object storage", such as alibaba cloud OSS, such as AWS S3. +You invoke ObjectStorageService API to do some CRUD operations on your binary file, e.g. query my file, delete my file, etc. + +## step 0. modify the configuration +Please modify the OSS configuration in the `configs/config_oss.json` + +```json +"grpc_config": { + "oss": { + "oss_demo": { + "type": "aws.oss", + "metadata": { + "basic_config":{ + "region": "your-oss-resource-region", + "endpoint": "your-oss-resource-endpoint", + "accessKeyID": "your-oss-resource-accessKeyID", + "accessKeySecret": "your-oss-resource-accessKeySecret" + } + } + } + } +} +``` + +## step 1. Deploy Layotto + +### **With Docker** +You can start Layotto with docker + +```bash +docker run -v "$(pwd)/configs/config_oss.json:/runtime/configs/config.json" -d -p 34904:34904 --name layotto layotto/layotto start +``` + +### **Compile locally (not for Windows)** +You can compile and run Layotto locally. + +> [!TIP|label: Not for Windows users] +> Layotto fails to compile under Windows. Windows users are recommended to deploy using docker-compose + +After downloading the project code to the local, switch the code directory and compile: + +```shell +cd ${project_path}/cmd/layotto +``` + +```shell @if.not.exist layotto +go build +``` + +Once finished, the layotto binary will be generated in the directory. + +Run it: + +```shell @background +./layotto start -c ../../configs/config_oss.json +``` + + + +## step 2. Run the client program to invoke Layotto ObjectStorageService API + +### **Go** +Build and run the golang [demo](https://github.com/mosn/layotto/blob/main/demo/oss/client.go) : + +```shell +cd ${project_path}/demo/oss/ +go build client.go + +# upload test3.txt with content "hello" to the bucket named `antsys-wenxuwan` +./client put antsys-wenxuwan test3.txt "hello" + +# get test3.txt in the bucket antsys-wenxuwan +./client get antsys-wenxuwan test3.txt + +# delete test3.txt +./client del antsys-wenxuwan test3.txt + +# list the files in the bucket antsys-wenxuwan +./client list antsys-wenxuwan + +``` + +### **Java** + + + + +## step 3. Stop containers and release resources + +### **Destroy the Docker container** +If you started Layotto with docker, you can destroy the container as follows: + +```bash +docker rm -f layotto +``` + + + +## Next step +### What does this client program do? +The demo client program uses the SDK provided by Layotto to invoke the Layotto ObjectStorageService API. + +The golang sdk is located in the `sdk` directory, and the java sdk is in https://github.com/layotto/java-sdk + +In addition to using sdk, you can also interact with Layotto directly through grpc in any language you like. + +### Details later, let's continue to experience other APIs +Explore other Quickstarts through the navigation bar on the left. + +### Reference + +[API reference](https://mosn.io/layotto/api/v1/s3.html) + +[Design doc of ObjectStorageService API ](zh/design/oss/design) + + + diff --git a/spec/proto/runtime/v1/html.tmpl b/docs/template/api_ref_html.tmpl similarity index 100% rename from spec/proto/runtime/v1/html.tmpl rename to docs/template/api_ref_html.tmpl diff --git a/spec/proto/runtime/v1/template.tmpl b/docs/template/api_ref_md.tmpl similarity index 100% rename from spec/proto/runtime/v1/template.tmpl rename to docs/template/api_ref_md.tmpl diff --git a/docs/template/quickstart.tmpl b/docs/template/quickstart.tmpl new file mode 100644 index 0000000000..d4073f4977 --- /dev/null +++ b/docs/template/quickstart.tmpl @@ -0,0 +1,123 @@ +{{range .Files}} {{$file_name := .Name}} {{if .HasServices}} {{range .Services}} +# {{.Name}} API demo + +This example shows how to invoke Layotto {{.Name}} API. + +{{.Description}} + +## step 1. Deploy Layotto + +### **With Docker** +You can start Layotto with docker + +```bash +docker run -v "$(pwd)/configs/config_standalone.json:/runtime/configs/config.json" -d -p 34904:34904 --name layotto layotto/layotto start +``` + +### **Compile locally (not for Windows)** +You can compile and run Layotto locally. + +> [!TIP|label: Not for Windows users] +> Layotto fails to compile under Windows. Windows users are recommended to deploy using docker + +After downloading the project code to the local, switch the code directory and compile: + +```shell +cd ${project_path}/cmd/layotto +``` + +```shell @if.not.exist layotto +go build +``` + +Once finished, the layotto binary will be generated in the directory. + +Run it: + +```shell @background +./layotto start -c ../../configs/config_standalone.json +``` + + + +## step 2. Run the client program to invoke Layotto {{.Name}} API + +### **Go** +Build and run the golang demo: + +```shell + cd ${project_path}/demo/{{$file_name}}/common/ + go build -o client + ./client -s "demo" +``` + +If the following information is printed, the demo is successful: + +```bash +TODO +``` + +### **Java** + +Download java sdk and examples: + +```shell @if.not.exist java-sdk +git clone https://github.com/layotto/java-sdk +``` + +```shell +cd java-sdk +``` + +Build the demo: + +```shell @if.not.exist examples-{{$file_name}}/target/examples-{{$file_name}}-1.1.0-jar-with-dependencies.jar +# build example jar +mvn -f examples-{{$file_name}}/pom.xml clean package +``` + +Run it: + +```shell +java -jar examples-{{$file_name}}/target/examples-{{$file_name}}-1.1.0-jar-with-dependencies.jar +``` + +If the following information is printed, the demo is successful: + +```bash +TODO +``` + + + +## step 3. Stop containers and release resources + +### **Destroy the Docker container** +If you started Layotto with docker, you can destroy the container as follows: + +```bash +docker rm -f layotto +``` + + + +## Next step +### What does this client program do? +The demo client program uses the SDK provided by Layotto to invoke the Layotto {{.Name}} API. + +The golang sdk is located in the `sdk` directory, and the java sdk is in https://github.com/layotto/java-sdk + +In addition to using sdk, you can also interact with Layotto directly through grpc in any language you like. + +### Details later, let's continue to experience other APIs +Explore other Quickstarts through the navigation bar on the left. + +### Reference + + + + + +{{end}} +{{end}} +{{end}} \ No newline at end of file diff --git a/docs/template/quickstart_zh.tmpl b/docs/template/quickstart_zh.tmpl new file mode 100644 index 0000000000..d7d275aade --- /dev/null +++ b/docs/template/quickstart_zh.tmpl @@ -0,0 +1,123 @@ +{{range .Files}} {{$file_name := .Name}} {{if .HasServices}} {{range .Services}} +# {{.Name}} API demo + +本示例演示如何调用 Layotto {{.Name}} API. + +{{.Description}} + +## step 1. 运行 Layotto + +### **With Docker** +您可以用 Docker 启动 Layotto + +```bash +docker run -v "$(pwd)/configs/config_standalone.json:/runtime/configs/config.json" -d -p 34904:34904 --name layotto layotto/layotto start +``` + +### **本地编译(不适合 Windows)** +您可以本地编译、运行 Layotto。 +> [!TIP|label: 不适合 Windows 用户] +> Layotto 在 Windows 下会编译失败。建议 Windows 用户使用 docker 部署 + +将项目代码下载到本地后,切换代码目录: + +```shell +cd ${project_path}/cmd/layotto +``` + +构建: + +```shell @if.not.exist layotto +go build +``` + +完成后目录下会生成 Layotto文件,运行它: + +```shell @background +./layotto start -c ../../configs/config_standalone.json +``` + + + +## step 2. 运行客户端程序,调用 Layotto {{.Name}} API + +### **Go** + +构建、运行 go 语言 demo: + +```shell + cd ${project_path}/demo/{{$file_name}}/common/ + go build -o client + ./client -s "demo" +``` + +打印出如下信息则代表调用成功: + +```bash +TODO +``` + +### **Java** + +下载 java sdk 和示例代码: + +```shell @if.not.exist java-sdk +git clone https://github.com/layotto/java-sdk +``` + +```shell +cd java-sdk +``` + +构建 examples: + +```shell @if.not.exist examples-{{$file_name}}/target/examples-{{$file_name}}-1.1.0-jar-with-dependencies.jar +# build example jar +mvn -f examples-{{$file_name}}/pom.xml clean package +``` + +运行: + +```shell +java -jar examples-{{$file_name}}/target/examples-{{$file_name}}-1.1.0-jar-with-dependencies.jar +``` + +打印出以下信息说明运行成功: + +```bash +TODO +``` + + + +## step 3. 销毁容器,释放资源 + +### **销毁 Docker container** +如果您是用 Docker 启动的 Layotto,可以按以下方式销毁容器: + +```bash +docker rm -f layotto +``` + + + +## 下一步 +### 这个客户端程序做了什么? +示例客户端程序中使用了 Layotto 提供的多语言 sdk,调用Layotto {{.Name}} API。 + +go sdk位于`sdk`目录下,java sdk 在 https://github.com/layotto/java-sdk + +除了使用sdk调用Layotto提供的API,您也可以用任何您喜欢的语言、通过grpc直接和Layotto交互。 + +### 细节以后再说,继续体验其他API +通过左侧的导航栏,继续体验别的API吧! + +### Reference + + + + + +{{end}} +{{end}} +{{end}} \ No newline at end of file diff --git a/docs/zh/_sidebar.md b/docs/zh/_sidebar.md index cdc80e8c3d..d289ebaba4 100644 --- a/docs/zh/_sidebar.md +++ b/docs/zh/_sidebar.md @@ -16,6 +16,7 @@ - 使用File API - [基于Minio](zh/start/file/minio.md) - [使用 OSS API](zh/start/oss/oss.md) + - [API插件:注册您自己的API](zh/start/api_plugin/helloworld.md) - 作为 Istio 的数据面 - [集成 Istio 1.10.6 演示](zh/start/istio/) diff --git a/docs/zh/api_reference/how_to_generate_api_doc.md b/docs/zh/api_reference/how_to_generate_api_doc.md index 36f25d284b..51bafb7b19 100644 --- a/docs/zh/api_reference/how_to_generate_api_doc.md +++ b/docs/zh/api_reference/how_to_generate_api_doc.md @@ -1,13 +1,16 @@ -# 如何基于proto文件生成代码、接口文档 +# 如何基于proto文件生成代码、文档 ```shell make proto ``` Then you get: -- `.pb.go` code +- `.pb.go` code - API reference docs -- updated sidebar in the doc site +- updated API reference list +- quickstart document (both chinese and english) +- updated sidebar (The tool will add the generated quickstart doc into the sidebar of https://mosn.io/layotto ) +- updated CI (The tool will add the generated quickstart doc into the CI script `etc/script/test-quickstart.sh`) That's all :) @@ -51,21 +54,8 @@ make proto.doc 该命令会用 docker 启动 protoc-gen-doc,生成文档 ### **用 docker 启动 protoc-gen-doc** -`make proto.doc` 等价于执行以下命令: +`make proto.doc` invokes the script `etc/script/generate-doc.sh`, which uses docker to run protoc-gen-doc. -``` -docker run --rm \ --v $(pwd)/docs/en/api_reference:/out \ --v $(pwd)/spec/proto/runtime/v1:/protos \ -pseudomuto/protoc-gen-doc --doc_opt=/protos/template.tmpl,runtime_v1.md runtime.proto -``` - -and +You can check `etc/script/generate-doc.sh` for more details. -```shell -docker run --rm \ --v $(pwd)/docs/en/api_reference:/out \ --v $(pwd)/spec/proto/runtime/v1:/protos \ -pseudomuto/protoc-gen-doc --doc_opt=/protos/template.tmpl,appcallback_v1.md appcallback.proto -``` \ No newline at end of file diff --git a/docs/zh/building_blocks/rpc/reference.md b/docs/zh/building_blocks/rpc/reference.md index 5828b4f64d..7fc03682bb 100644 --- a/docs/zh/building_blocks/rpc/reference.md +++ b/docs/zh/building_blocks/rpc/reference.md @@ -4,7 +4,7 @@ Layotto的RPC API基于[Mosn](https://mosn.io/docs/overview/)的grpc handler设 RPC API的接口与[Dapr](https://docs.dapr.io/zh-hans/developing-applications/building-blocks/service-invocation/service-invocation-overview/)一致,可以在代码[invoke.go](https://github.com/mosn/layotto/blob/3802c4591181fdbcfb7dd07cbbdbadeaaada650a/sdk/go-sdk/client/invoke.go)中看到接口的具体设计细节。 -使用 Layotto RPC API 进行服务调用,您的应用程序可以使用标准 HTTP 或 [X-Protocol](https://www.servicemesher.com/blog/x-protocol-common-address-solution/) 协议可靠且安全地与其他应用程序通信. +使用 Layotto RPC API 进行服务调用,您的应用程序可以使用标准 HTTP 或 [X-Protocol](https://cloudnative.to/blog/x-protocol-common-address-solution/) 协议可靠且安全地与其他应用程序通信. ![sidecar](https://mosn.io/en/docs/concept/sidecar-pattern/sidecar-pattern.jpg) diff --git a/docs/zh/design/oss/oss-api-design.md b/docs/zh/design/oss/design.md similarity index 100% rename from docs/zh/design/oss/oss-api-design.md rename to docs/zh/design/oss/design.md diff --git a/docs/zh/start/oss/oss.md b/docs/zh/start/oss/oss.md index c4480fe108..b3a1dfafc0 100644 --- a/docs/zh/start/oss/oss.md +++ b/docs/zh/start/oss/oss.md @@ -7,7 +7,7 @@ Layotto提供了访问OSS的示例 [demo](https://github.com/mosn/layotto/blob/m ### step 1. 启动layotto -layotto提供了aws的配置文件`configs/oss.json`,配置文件内容如下所示: +layotto提供了aws的配置文件`configs/config_oss.json`,配置文件内容如下所示: ```json "grpc_config": { @@ -54,7 +54,7 @@ go build -o layotto Layotto提供了访问文件的示例 [demo](https://github.com/mosn/layotto/blob/main/demo/oss/client.go) ```shell -cd ${project_path}/demo/file/s3/ +cd ${project_path}/demo/oss/ go build client.go # 上传名为test3.txt的文件到名为antsys-wenxuwan的bucket下,内容为"hello" diff --git a/docs/zh/start/sequencer/start.md b/docs/zh/start/sequencer/start.md index 4f475309e4..1e722cc9b9 100644 --- a/docs/zh/start/sequencer/start.md +++ b/docs/zh/start/sequencer/start.md @@ -96,7 +96,7 @@ Demo success! #### **Java** -Download java sdk and examples: +下载 java sdk 和示例代码: ```shell @if.not.exist java-sdk git clone https://github.com/layotto/java-sdk diff --git a/etc/script/generate-doc.sh b/etc/script/generate-doc.sh index d0afce62e0..cb968624d7 100644 --- a/etc/script/generate-doc.sh +++ b/etc/script/generate-doc.sh @@ -1,24 +1,155 @@ project_path=$(pwd) +tpl_path="${project_path}/docs/template" +quickstart_path="${project_path}/docs/en/start" +quickstart_path_zh="${project_path}/docs/zh/start" +sidebar_path="${project_path}/docs/_sidebar.md" +sidebar_path_zh="${project_path}/docs/zh/_sidebar.md" +qs_ci_path="${project_path}/etc/script/test-quickstart.sh" +true=0 +false=1 -echo "===========> Generating docs for spec/proto/extension/v1/" -# generate docs for extension/v1 -res=$(cd spec/proto/extension/v1/ && ls -d *) -for r in $res; do +needGenerateQuickstart() { + file=$1 + + # check no `@exclude` tag + if [ $(grep "@exclude quickstart generator" $file | wc -l) -eq 0 ]; then + # check if there's a gRPC service in it + if [ $(grep "service " $file | wc -l) -gt 0 ]; then + return $true + fi + fi + return $false +} + +addQuickstartIntoCI() { + doc=$1 + + if [ $(grep $doc ${qs_ci_path} | wc -l) -eq 0 ]; then + sed -i "" '/quickstarts_in_default="/a \ + '${doc}'\ + ' ${qs_ci_path} + fi +} + +generateQuickstart() { + proto_path=$1 + proto_name=$2 + nickname=$3 + api_reference_url=$4 + + # 0. check if it needs our help + needGenerateQuickstart "${proto_path}/${proto_name}" + if [ $? -eq $false ]; then + return 0 + fi + + # 1. copy and rename the proto file + cp "${proto_path}/${proto_name}" "${proto_path}/${nickname}" + + # 2. generate the english quickstart document + # check if the quickstart doc already exists + if ! test -e "${quickstart_path}/${nickname}/start.md"; then + echo "===========> Generating the english quickstart document for ${proto_path}/${proto_name}" + docker run --rm \ + -v ${quickstart_path}/${nickname}:/out \ + -v ${project_path}/${proto_path}:/protos \ + -v ${tpl_path}:/tpl \ + pseudomuto/protoc-gen-doc --doc_opt=/tpl/quickstart.tmpl,start.md ${nickname} + + # modify api reference url + if ! test -z ${api_reference_url}; then + sed -i "" "s##[API Reference](${api_reference_url})#" ${quickstart_path}/${nickname}/start.md + fi + + # modify design doc url + if test -e "docs/zh/design/${nickname}/design.md"; then + sed -i "" "s##[Design doc](zh/design/${nickname}/design)#" ${quickstart_path}/${nickname}/start.md + fi + fi + + # 3. add the quickstart into the sidebar + if [ $(grep "en/start/${nickname}/start" ${sidebar_path} | wc -l) -eq 0 ]; then + sed -i "" '/quickstart_generator/a \ +'"\ "'- [Use '${nickname}' API](en/start/'${nickname}'/start) \ +' "${sidebar_path}" + fi + + # 4. generate the chinese quickstart document + # check if the chinese quickstart doc already exists + if ! test -e "${quickstart_path_zh}/${nickname}/start.md"; then + echo "===========> Generating the chinese quickstart document for ${proto_path}/${proto_name}" + docker run --rm \ + -v ${quickstart_path_zh}/${nickname}:/out \ + -v ${project_path}/${proto_path}:/protos \ + -v ${tpl_path}:/tpl \ + pseudomuto/protoc-gen-doc --doc_opt=/tpl/quickstart_zh.tmpl,start.md ${nickname} + + # modify api reference url + if ! test -z ${api_reference_url}; then + sed -i "" "s##[API Reference](${api_reference_url})#" ${quickstart_path_zh}/${nickname}/start.md + fi + + # modify design doc url + if test -e "docs/zh/design/${nickname}/design.md"; then + sed -i "" "s##[Design doc](zh/design/${nickname}/design)#" ${quickstart_path_zh}/${nickname}/start.md + fi + fi + + # 5. add the chinese quickstart into the sidebar + if [ $(grep "zh/start/${nickname}/start" ${sidebar_path_zh} | wc -l) -eq 0 ]; then + sed -i "" '/quickstart_generator/a \ +'"\ "'- [使用 '${nickname}' API](zh/start/'${nickname}'/start) \ +' "${sidebar_path_zh}" + fi + + # 6. add the quickstart doc into the test-quickstart.sh + addQuickstartIntoCI "docs/en/start/${nickname}/start.md" + addQuickstartIntoCI "docs/zh/start/${nickname}/start.md" + + # 7. clean up + rm "${proto_path}/${nickname}" +} + +# 1. generate docs for extension/v1 +proto_path="spec/proto/extension/v1" +echo "===========> Generating docs for ${proto_path}" +res=$(cd $proto_path && ls -d *) +for directory in $res; do + echo "===========> Generating the API reference for ${proto_path}/${directory}" + # 1.1. generate the API reference docker run --rm \ - -v $project_path/docs/api/v1:/out \ - -v $project_path/spec/proto/extension/v1/$r:/protos \ - -v $project_path/spec/proto/runtime/v1:/protos/tpl \ - pseudomuto/protoc-gen-doc --doc_opt=/protos/tpl/html.tmpl,$r.html + -v ${project_path}/docs/api/v1:/out \ + -v ${project_path}/${proto_path}/${directory}:/protos \ + -v ${tpl_path}:/tpl \ + pseudomuto/protoc-gen-doc --doc_opt=/tpl/api_ref_html.tmpl,${directory}.html + + # 1.2. generate the quickstart document + # find all protos + protos=$(cd ${proto_path}/${directory} && ls *.proto) + for p in ${protos}; do + generateQuickstart "${proto_path}/${directory}" "${p}" "${directory}" "https://mosn.io/layotto/api/v1/${directory}.html" + done done -# generate docs for runtime/v1 +# 2. generate docs for runtime/v1 echo "===========> Generating docs for spec/proto/runtime/v1/" +proto_path="spec/proto/runtime/v1" +# 2.1. generate the API reference +echo "===========> Generating the API reference for spec/proto/runtime/v1/" docker run --rm \ - -v $project_path/docs/api/v1:/out \ - -v $project_path/spec/proto/runtime/v1:/protos \ - pseudomuto/protoc-gen-doc --doc_opt=/protos/html.tmpl,runtime.html + -v ${project_path}/docs/api/v1:/out \ + -v ${project_path}/${proto_path}:/protos \ + -v ${tpl_path}:/tpl \ + pseudomuto/protoc-gen-doc --doc_opt=/tpl/api_ref_html.tmpl,runtime.html +# 2.2. generate the quickstart doc +# find all protos +protos=$(cd ${proto_path} && ls *.proto) +for p in ${protos}; do + nickname=$(basename ${p} | cut -d . -f1) + generateQuickstart "${proto_path}" "${p}" "${nickname}" "https://mosn.io/layotto/api/v1/runtime.html" +done -# update the sidebar +# 3. update the api reference index cd $project_path sidebar_zh=docs/zh/api_reference/README.md sidebar=docs/en/api_reference/README.md @@ -29,13 +160,16 @@ sed -i "" '/.*: \[.*\]\(.*\)/d' $sidebar_zh sed -i "" '/.*: \[.*\]\(.*\)/d' $sidebar # reinsert the reference lines for r in $res; do - echo "$r: [spec/proto/extension/v1/$r](https://mosn.io/layotto/api/v1/$r.html) \n" >> $sidebar_zh - echo "$r: [spec/proto/extension/v1/$r](https://mosn.io/layotto/api/v1/$r.html) \n" >> $sidebar + echo "$r: [spec/proto/extension/v1/$r](https://mosn.io/layotto/api/v1/$r.html) \n" >>$sidebar_zh + echo "$r: [spec/proto/extension/v1/$r](https://mosn.io/layotto/api/v1/$r.html) \n" >>$sidebar done # delete last line sed -i "" '$d' $sidebar_zh sed -i "" '$d' $sidebar +# 4. update the sidebar +cd $project_path +# TODO cd $project_path # generate index for api references diff --git a/spec/proto/extension/v1/s3/oss.proto b/spec/proto/extension/v1/s3/oss.proto index 9d46e2113a..e31ebe11e5 100644 --- a/spec/proto/extension/v1/s3/oss.proto +++ b/spec/proto/extension/v1/s3/oss.proto @@ -9,8 +9,11 @@ import "google/protobuf/empty.proto"; option go_package = "mosn.io/layotto/spec/proto/extension/v1/s3;s3"; -// ObjectStorageService +/* @exclude quickstart generator */ +// ObjectStorageService is an abstraction for blob storage or so called "object storage", such as alibaba cloud OSS, such as AWS S3. +// You invoke ObjectStorageService API to do some CRUD operations on your binary file, e.g. query my file, delete my file, etc. service ObjectStorageService{ + //Object CRUD API //Adds an object to a bucket. //Refer https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html diff --git a/spec/proto/runtime/v1/appcallback.proto b/spec/proto/runtime/v1/appcallback.proto index ef6abe64df..f190f19244 100644 --- a/spec/proto/runtime/v1/appcallback.proto +++ b/spec/proto/runtime/v1/appcallback.proto @@ -9,6 +9,7 @@ option go_package = "mosn.io/layotto/spec/proto/runtime/v1;runtime"; option java_outer_classname = "AppCallbackProto"; option java_package = "spec.proto.runtime.v1"; +/* @exclude quickstart generator */ // AppCallback V1 allows user application to interact with runtime. // User application needs to implement AppCallback service if it needs to // receive message from runtime. diff --git a/spec/proto/runtime/v1/email.proto b/spec/proto/runtime/v1/email.proto new file mode 100644 index 0000000000..82b7bb7efa --- /dev/null +++ b/spec/proto/runtime/v1/email.proto @@ -0,0 +1,113 @@ +syntax = "proto3"; + +package spec.proto.runtime.v1; + +import "google/protobuf/empty.proto"; +import "google/protobuf/any.proto"; + +option go_package = "mosn.io/layotto/spec/proto/runtime/v1;runtime"; + +// EmailTemplateService is used to send emails with templates +service EmailTemplateService { + + // Send an email with template + rpc SendEmailWithTemplate(SendEmailWithTemplateRequest) returns (SendEmailWithTemplateResponse) {} + +} + +// EmailTemplateService is used to send emails. +service EmailService { + + // Send an email. + rpc SendEmail(SendEmailRequest) returns (SendEmailResponse) {} + +} + +// SendEmailWithTemplateRequest is the message send to email. +message SendEmailWithTemplateRequest { + + // The saas service name, like 'aliyun.email'/'aws.ses'/'...' + // If your system uses multiple IVR services at the same time, + // you can specify which service to use with this field. + string service_name = 1; + + // Required. + EmailTemplate template = 2; + + // Required. The Email subject. + string subject = 3; + + // Required. + EmailAddress address = 4; + +} + +// Address information +message EmailAddress{ + + // Required. The Email sender address. + string from = 1; + + // Required. The Email destination addresses. + repeated string to = 2; + + // Optional. To whom the mail is cc + repeated string cc = 3; +} + +// Email template +message EmailTemplate{ + + // Required + string template_id = 1; + + // Required + map template_params = 2; + +} + +// Response of `SendEmailWithTemplate` method +message SendEmailWithTemplateResponse { + + // The saas requestId. + string request_id = 1; + +} + +// SendEmailRequest is the message send to email. +message SendEmailRequest { + + // The saas service name, like 'aliyun.email'/'aws.ses'/'...' + // If your system uses multiple IVR services at the same time, + // you can specify which service to use with this field. + string service_name = 1; + + // Required. + string setting_id = 2; + + // Required. The Email subject. + string subject = 3; + + // Required. + Content content = 4; + + // Required. + EmailAddress address = 5; + +} + +// Email content +message Content{ + + // Required. + string text = 1; + +} + +// The response of `SendEmail` method +message SendEmailResponse { + + // The saas requestId. + string request_id = 1; + +} diff --git a/spec/proto/runtime/v1/phone_call.proto b/spec/proto/runtime/v1/phone_call.proto new file mode 100644 index 0000000000..adfda76eb9 --- /dev/null +++ b/spec/proto/runtime/v1/phone_call.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package spec.proto.runtime.v1; + +import "google/protobuf/empty.proto"; +import "google/protobuf/any.proto"; + +option go_package = "mosn.io/layotto/spec/proto/runtime/v1;runtime"; + +// PhoneCallService is one of Notify APIs. It's used to send voice messages +service PhoneCallService { + + // Send voice using the specific template + rpc SendVoiceWithTemplate(SendVoiceWithTemplateRequest) returns (SendVoiceWithTemplateResponse) {} + +} + +// The request of SendVoiceWithTemplate method +message SendVoiceWithTemplateRequest{ + + // If your system uses multiple IVR services at the same time, + // you can specify which service to use with this field. + string service_name = 1; + + // Required + VoiceTemplate template = 2; + + // Required + repeated string to_mobile = 3; + + // This field is required by some cloud providers. + string from_mobile = 4; + +} + +// VoiceTemplate +message VoiceTemplate{ + + // Required + string template_id = 1; + + // Required + map template_params = 2; + +} + +// The response of `SendVoiceWithTemplate` method +message SendVoiceWithTemplateResponse{ + + // Id of this request. + string request_id = 1; + +} diff --git a/spec/proto/runtime/v1/runtime.proto b/spec/proto/runtime/v1/runtime.proto index a5772e4723..330afb4376 100644 --- a/spec/proto/runtime/v1/runtime.proto +++ b/spec/proto/runtime/v1/runtime.proto @@ -9,6 +9,7 @@ option go_package = "mosn.io/layotto/spec/proto/runtime/v1;runtime"; option java_outer_classname = "RuntimeProto"; option java_package = "spec.proto.runtime.v1"; +/* @exclude quickstart generator */ // Runtime encapsulates variours Runtime APIs(such as Configuration API, Pub/Sub API, etc) service Runtime { //SayHello used for test
Method NameRequest TypeResponse TypeDescription