marsevilspirit opened a new pull request, #2900:
URL: https://github.com/apache/dubbo-go/pull/2900

   The purpose of this PR is to reduce the burden on the ProtocolConfig struct 
by adding TripleConfig, which handles the config and options related only to 
the Triple Protocol, thereby enhancing logical clarity.
   
   For example, with the current code, if we want to configure the parameters 
related to the Triple protocol keepalive, how should we write it:
   
   ```go
        cli, err := client.NewClient(
                client.WithClientURL("127.0.0.1:20000"),
                client.WithClientProtocolTriple(),
                client.WithKeepAliveInterval(10*time.Second),
                client.WithKeepAliveTimeout(20*time.Second),
        )
   ```
   
   At first glance, it seems reasonable, but these two options can also be used 
when I start other protocols, for example:
   
   ```go
        cli, err := client.NewClient(
                client.WithClientURL("127.0.0.1:20000"),
                client.WithClientProtocolDubbo(),
                client.WithKeepAliveInterval(10*time.Second),
                client.WithKeepAliveTimeout(20*time.Second),
        )
   ```
   
   Well, this is unreasonable because **WithKeepAliveInterval** and 
**WithKeepAliveTimeout** only take effect for the Triple protocol, yet they can 
be used like this. This creates a learning cost for users, for example, users 
are not clear that these two options only take effect for the Triple protocol, 
and when they write other protocols, they mistakenly believe they will take 
effect, but actually do not achieve the expected result, debugging for a long 
time only to find out they only apply to the Triple protocol. Therefore, we 
should enhance the specificity of options and impose restrictions at the API 
level.
   
   Moreover, the way parameters are passed and the structure above is also a 
problem. The API above passes parameters and structures like this:
   
   ```go
   // ProtocolConfig is a shared config for all protocols, it is inappropriate 
to place parameters unique to Triple here,
   // as the number of parameters grows, ProtocolConfig will become 
increasingly bloated, and we need to find a way to solve this problem.
   type ProtocolConfig struct {
        ...
        MaxServerSendMsgSize string
        MaxServerRecvMsgSize string
        ...
   }
   ```
   
   ```go
                // The same problem, as the number of parameters increases, the 
URL configuration will become increasingly bloated,
                // and the parameters in the URL are difficult to track and 
extract, relying only on the key to extract one by one and judge whether it is 
valid.
                ivkURL := common.NewURLWithOptions(
                        ...
                        common.WithParamsValue(constant.MaxServerSendMsgSize, 
protocolConf.MaxServerSendMsgSize),
                        common.WithParamsValue(constant.MaxServerRecvMsgSize, 
protocolConf.MaxServerRecvMsgSize),
                        ...
                )
                
                // Parameters have to be extracted like this, which is too 
inefficient, and the code duplication rate is too high, leading to complete 
confusion with many parameters.
                url.GetParam(constant.MaxServerRecvMsgSize, "")
                url.GetParam(constant.MaxServerSendMsgSize, "")
                ...
   ```
   
   I want to create a highly unified API for client and server, for example:
   
   ```go
        [srv/cli], err := [server/client].New[Server/Client](
                ...
                [server.client].With[Server/Client]Protocol(
                        protocol.With[XXX](),
                        protocol.With[Triple/...](
                                [triple/...].WithXXX(xxx...),
                                ...
                        ),
                ),
                ...
        )
   ```
   
   The actual API looks like this:
   
   server:
   
   ```go
        srv, err := server.NewServer(
                server.WithServerProtocol(
                        protocol.WithPort(20000),
                        protocol.WithTriple(
                                triple.WithMaxServerRecvMsgSize("30mb"),
                                triple.WithMaxServerSendMsgSize("30mb"),
                        ),
                ),
        )
   ```
   
   client:
   
   ```go
        cli, err := client.NewClient(
                client.WithClientURL("127.0.0.1:20000"),
                client.WithClientProtocol(
                        protocol.WithTriple(
                                triple.WithKeepAliveInterval(30*time.Second),
                                triple.WithKeepAliveTimeout(30*time.Second),
                        ),
                ),
        )
   ```
   
   This way, there will be no misuse of options that do not take effect.
   
   How did I achieve interface unification?
   
   Mainly by defining interfaces:
   
   ```go
   // ClientOption is an option for the Client
   type ClientOption interface {
        applyToClient(*ClientOptions)
   }
   
   // ServerOption is an option for the Server
   type ServerOption interface {
        applyToServer(*ServerOptions)
   }
   
   // Option is a general option, meaning both Client and Server can use it
   type Option interface {
        ClientOption
        ServerOption
   }
   ```
   
   How to implement shared options for client and server, I will take the 
Triple Protocol as an example:
   
   ```go
   type tripleOption struct {
        triOpts triple.Options
   }
   
   // If the Client can call it, implement the applyToClient method
   func (o *tripleOption) applyToClient(config *ClientOptions) {
        config.ProtocolClient.TripleConfig = o.triOpts.Triple
   }
   
   // If the Server can call it, implement the applyToServer method
   func (o *tripleOption) applyToServer(config *ServerOptions) {
        config.Protocol.TripleConfig = o.triOpts.Triple
   }
   
   // The Triple Protocol must be a common option for both Server and Client
   func WithTriple(opts ...triple.Option) Option {
        triSrvOpts := triple.NewOptions(opts...)
   
        return &tripleOption{
                triOpts: *triSrvOpts,
        }
   }
   ```
   
   After processing all options, just apply them collectively to 
[Server/Client]:
   
   ```go
   func New[Server/Client]Options(opts ...[Server/Client]Option) 
*[Server/Client]Options {
        defOpts := default[Server/Client]Options()
        for _, opt := range opts {
                // Apply here
                opt.applyTo[Server/Client](defOpts)
        }
   
        if defOpts.ID == "" {
                if defOpts.Protocol.Name == "" {
                        // should be the same as default value of 
config.ProtocolConfig.Protocol
                        defOpts.ID = constant.TriProtocol
                } else {
                        defOpts.ID = defOpts.Protocol.Name
                }
        }
   
        return defOpts
   }
   ```
   
   How did I simplify parameter passing?
   
   I created the TripleConfig struct and made modifications to the 
ProtocolConfig struct:
   
   ```go
   type TripleConfig struct {
        // Parameters unique to the triple protocol are placed in this struct
        KeepAliveInterval string
        KeepAliveTimeout  string
        ...
   }
   
   type ProtocolConfig struct {
        ...
        TripleConfig *TripleConfig
        ...
   }
   ```
   
   The method of passing parameters is also very efficient:
   
   ```go
        // Directly passing the TripleConfig struct
        ivkURL := common.NewURLWithOptions(
                ...
                common.WithAttribute(constant.TripleConfigKey, 
protocolConf.TripleConfig),
                ...
        )
        
        // Extracting is also done directly by extracting the struct
        // tripleConf contains all the parameters we want
        var tripleConf *global.TripleConfig
        tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
        if ok {
                tripleConf = tripleConfRaw.(*global.TripleConfig)
        }
   ```
   
   Usage of TripleConfig in YAML files:
   
   server:
   
   ```yaml
   # dubbo server yaml configure file
   dubbo:
     registries:
       demoZK:
         protocol: zookeeper
         timeout: 10s
         address: 127.0.0.1:2181
     protocols:
       tripleProtocol:
         name: tri
         port: 20000
         # triple is the tripleConfig
         triple:
           max-server-send-msg-size: 20mb
           max-server-recv-msg-size: 20mb
     provider:
       services:
         GreetTripleServer:
           interface: com.apache.dubbo.sample.Greeter
   ```
   
   client:
   
   ```yaml
   # dubbo client yaml configure file
   dubbo:
     registries:
       demoZK:
         protocol: zookeeper
         timeout: 3s
         address: 127.0.0.1:2181
     consumer:
       references:
         GreetServiceImpl:
              # I know this configuration looks a bit strange, but this 
protocol is for compatibility with the config package
              # After solving the config package issue, the protocol-config may 
be renamed to protocol
              # Unifying the use of protocol configuration
              # Here, the protocol is a string type, which makes me laugh XD
              # For compatibility, we need version 4.0.0 to remove it
           protocol: tri
           protocol-config:
             # triple is the tripleConfig
             triple:
               keep-alive-interval: 10s
               keep-alive-timeout: 20s
           interface: com.apache.dubbo.sample.Greeter
           registry: demoZK
           retries: 3
           timeout: 3000
   
   # The new version should look like this
   dubbo:
     registries:
       demoZK:
         protocol: zookeeper
         timeout: 3s
         address: 127.0.0.1:2181
     consumer:
       references:
         GreetServiceImpl:
              # Looks much better, doesn't it?
           protocol:
                name: tri
             triple:
               keep-alive-interval: 10s
               keep-alive-timeout: 20s
           interface: com.apache.dubbo.sample.Greeter
           registry: demoZK
           retries: 3
           timeout: 3000
   ```
   
   The benefits brought by this PR:
   
   1. Greatly expands the flexibility of protocol options
   2. Solves the problem of URLs becoming increasingly bloated
   3. Addresses the issue of ProtocolConfig becoming increasingly bloated
   4. Optimizes the usage of APIs related to Triple, further reducing the 
learning cost for users


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to