MickMake / GoSungrow

GoLang implementation to access the iSolarCloud API updated by SunGrow inverters.
https://mickmake.com/
GNU General Public License v2.0
148 stars 42 forks source link

4.0 architecture idea #35

Open jpillora opened 1 year ago

jpillora commented 1 year ago

This suggestion is a fairly big change, but i think would drastically reduce: the number of files, lines of code, compile time, and the overall complexity of the code base.

In the code below, the goal is to minimise the amount of generated code while maintaining a nice API for the user:


// ===================================================
// HAND WRITTEN CODE

type Data = map[string]interface{}

type Config struct {
    Version string
    BaseURL string
}

type Client struct {
    Config
    Services services.Services
}

func NewClient(config Config) *Client {
    client := &Client{Config: config}
    client.Services.init(client)
    return client
}

func (c *Client) request(service, endpoint string, data Data) (Data, error) {
    url := c.Config.BaseURL + "/" + c.Config.Version + "/" + service + "/" + endpoint
    // make request
}

// ===================================================
// GENERATED CODE (all generated code in one place: gen/)

// generate [gen/services/services.go]
package services

type Services struct {
    AliSms
    App
    MttvScreen
}

// general init all, pass Client into all services
func (s *Services) init(client *Client) {
    s.AliSms = AliSms{Name: "AliSms", client: client}
    s.App = App{Name: "App", client: client}
    s.MttvScreen = MttvScreen{Name: "MttvScreen", client: client}
}

// generate service [gen/services/service_ali_sms.go]
package services
// AliSmsService    msgDownwardStatusReceipt    /v1/messageService/msgDownwardStatusReceipt
// becomes:
type AliSms struct {
    client *Client
    Name string
    State int
}

func (s *AliSms) MsgDownwardStatusReceipt(data Data) (Data, error) {
    return s.client.request(s.Name, "messageService/msgDownwardStatusReceipt", data)
}

// generate service [gen/services/service_app.go]
package services
// AppService   acceptPsSharing /v1/powerStationService/acceptPsSharing
// AppService   activateEmail   /v1/userService/activateEmail
// becomes
type App struct {
    client *Client
    Name string
    State int
}

func (s *App) AcceptPsSharing(data Data) (Data, error) {
    return s.client.request(s.Name, "powerStationService/acceptPsSharing", data)
}

func (s *App) ActivateEmail(data Data) (Data, error) {
    return s.client.request(s.Name, "userService/activateEmail", data)
}

// ===================================================
// USER CODE

client, err := NewClient(Config{ ... })
if err != nil {
   // handle
}
out, err := client.Services.App.ActivateEmail(data{
   "param1": 42
})
if err != nil {
   // handle
}
// out holds response
jpillora commented 1 year ago

Disclaimer: I dont fully understand the codebase, so feel free to correct any inaccuracies!