2020-10-13 05:24:11 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Protocol struct {
|
|
|
|
Types map[string]map[string]*Type
|
|
|
|
Actions map[string]map[string]*Action
|
|
|
|
}
|
|
|
|
|
|
|
|
type Type struct {
|
|
|
|
Fields map[string]*DataType
|
|
|
|
Request bool `json:"-"`
|
|
|
|
Doc string
|
|
|
|
}
|
|
|
|
|
|
|
|
type DataType struct {
|
|
|
|
List bool
|
|
|
|
Type string
|
|
|
|
Version string
|
|
|
|
FieldName string
|
|
|
|
Doc string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Action struct {
|
|
|
|
FnName string
|
|
|
|
Request string
|
|
|
|
Response string
|
|
|
|
Doc string
|
|
|
|
}
|
|
|
|
|
|
|
|
type StructsTemplateInput struct {
|
|
|
|
Types map[string]*Type
|
|
|
|
Version string
|
|
|
|
ImportVersions []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type ActionsTemplateInput struct {
|
|
|
|
Actions map[string]*Action
|
|
|
|
Version string
|
|
|
|
Responses bool
|
|
|
|
}
|
|
|
|
|
|
|
|
var typeMap = map[string]string{
|
|
|
|
"int": "int32",
|
|
|
|
"Integer": "int32",
|
|
|
|
"Boolean": "bool",
|
|
|
|
"long": "int64",
|
|
|
|
"Long": "int64",
|
|
|
|
"UUID": "string",
|
|
|
|
"boolean": "bool",
|
|
|
|
"String": "string",
|
|
|
|
"Map": "map[string]string", // TODO: make signald print the actual key and value types
|
2021-07-02 06:15:11 +00:00
|
|
|
"Object": "interface{}",
|
2020-10-13 05:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var fieldNameMap = map[string]string{
|
|
|
|
"id": "ID",
|
|
|
|
"recipientGroupId": "RecipientGroupID",
|
|
|
|
"uuid": "UUID",
|
2021-01-30 00:45:29 +00:00
|
|
|
"gv1-migration": "Gv1Migration",
|
2020-10-13 05:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DataType) fixForVersion(field, version string) {
|
|
|
|
response, ok := typeMap[d.Type]
|
|
|
|
if ok {
|
|
|
|
if d.Type == "byte" && d.List {
|
|
|
|
d.List = false
|
|
|
|
}
|
|
|
|
d.Type = response
|
|
|
|
} else {
|
|
|
|
if d.Version == version || d.Version == "" {
|
|
|
|
d.Type = fmt.Sprintf("*%s", d.Type)
|
|
|
|
} else {
|
|
|
|
d.Type = fmt.Sprintf("*%s.%s", d.Version, d.Type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldName, ok := fieldNameMap[field]
|
|
|
|
if ok {
|
|
|
|
d.FieldName = fieldName
|
|
|
|
} else {
|
2021-02-18 07:32:28 +00:00
|
|
|
components := strings.Split(field, "_")
|
|
|
|
for i, c := range components {
|
|
|
|
components[i] = strings.Title(c)
|
|
|
|
}
|
|
|
|
d.FieldName = strings.Join(components, "")
|
2020-10-13 05:24:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var response Protocol
|
|
|
|
err := json.NewDecoder(os.Stdin).Decode(&response)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nError parsing stdin")
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpl, err := template.ParseGlob("tools/generator/*.tmpl")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nError parsing templates from tools/generator/*.tmpl")
|
|
|
|
}
|
|
|
|
|
|
|
|
for version, actions := range response.Actions {
|
|
|
|
inputs := ActionsTemplateInput{Version: version, Responses: false}
|
|
|
|
for action, a := range actions {
|
|
|
|
actions[action].FnName = strings.Title(action)
|
|
|
|
if a.Request != "" {
|
|
|
|
response.Types[version][a.Request].Request = true
|
|
|
|
}
|
|
|
|
if a.Response != "" {
|
|
|
|
inputs.Responses = true
|
|
|
|
}
|
2021-02-18 07:32:28 +00:00
|
|
|
if r, ok := typeMap[a.Response]; ok {
|
|
|
|
a.Response = r
|
|
|
|
}
|
2020-10-13 05:24:11 +00:00
|
|
|
}
|
|
|
|
inputs.Actions = actions
|
|
|
|
outputDir := fmt.Sprintf("signald/client-protocol/%s", version)
|
|
|
|
err = os.MkdirAll(outputDir, os.ModePerm)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error creating", outputDir, err)
|
|
|
|
}
|
|
|
|
outputFilename := fmt.Sprintf("%s/%s", outputDir, "requests.go")
|
|
|
|
log.Println("Opening", outputFilename)
|
|
|
|
f, err := os.Create(outputFilename)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nfailed to open output file ", outputFilename)
|
|
|
|
}
|
|
|
|
err = tmpl.ExecuteTemplate(f, "requests.go.tmpl", inputs)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nfailed to render template")
|
|
|
|
}
|
|
|
|
err = exec.Command("gofmt", "-w", outputFilename).Run()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, " error running gofmt on ", outputFilename)
|
|
|
|
}
|
|
|
|
fmt.Println(outputFilename)
|
|
|
|
}
|
|
|
|
|
|
|
|
for version, types := range response.Types {
|
|
|
|
inputs := StructsTemplateInput{Version: version}
|
|
|
|
for typeName, t := range types {
|
|
|
|
for fieldName, field := range t.Fields {
|
|
|
|
types[typeName].Fields[fieldName].fixForVersion(fieldName, version)
|
|
|
|
if field.Version != "" && field.Version != version {
|
|
|
|
found := false
|
|
|
|
for _, v := range inputs.ImportVersions {
|
|
|
|
if v == field.Version {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
inputs.ImportVersions = append(inputs.ImportVersions, field.Version)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inputs.Types = types
|
|
|
|
outputDir := fmt.Sprintf("signald/client-protocol/%s", version)
|
|
|
|
err = os.MkdirAll(outputDir, os.ModePerm)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error creating", outputDir, err)
|
|
|
|
}
|
|
|
|
outputFilename := fmt.Sprintf("%s/%s", outputDir, "structs.go")
|
|
|
|
log.Println("Opening", outputFilename)
|
|
|
|
f, err := os.Create(outputFilename)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nfailed to open output file ", outputFilename)
|
|
|
|
}
|
|
|
|
err = tmpl.ExecuteTemplate(f, "structs.go.tmpl", inputs)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, "\nfailed to render template")
|
|
|
|
}
|
|
|
|
err = exec.Command("gofmt", "-w", outputFilename).Run()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err, " error running gofmt on ", outputFilename)
|
|
|
|
}
|
|
|
|
fmt.Println(outputFilename)
|
|
|
|
}
|
|
|
|
}
|