Documentation
¶
Index ¶
Constants ¶
View Source
const ControllerTemplate = `` /* 1176-byte string literal not displayed */
View Source
const ControllersRegisterTemplate = `// generated code - do not edit package controllers import ( "context" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "log" "math" "net/http" "net/url" "strconv" "strings" "time" "{{PkgPathRoot}}/orm" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) // genQuery return the name of the column func genQuery(columnName string) string { return fmt.Sprintf("%s = ?", columnName) } // A GenericError is the default error message that is generated. // For certain status codes there are more appropriate error structures. // // swagger:response genericError type GenericError struct { // in: body Body struct { Code int32 ` + "`" + `json:"code"` + "`" + ` Message string ` + "`" + `json:"message"` + "`" + ` } ` + "`" + `json:"body"` + "`" + ` } // A ValidationError is an that is generated for validation failures. // It has the same fields as a generic error but adds a Field property. // // swagger:response validationError type ValidationError struct { // in: body Body struct { Code int32 ` + "`" + `json:"code"` + "`" + ` Message string ` + "`" + `json:"message"` + "`" + ` Field string ` + "`" + `json:"field"` + "`" + ` } ` + "`" + `json:"body"` + "`" + ` } // registerControllers register controllers func registerControllers(r *gin.Engine) { v1 := r.Group("/api/{{PkgPathRoot}}") { // insertion point for registrations{{` + string(rune(ControllersDeclaration)) + `}} v1.GET("/v1/commitfrombacknb", GetController().GetLastCommitFromBackNb) v1.GET("/v1/pushfromfrontnb", GetController().GetLastPushFromFrontNb) v1.GET("/v1/ws/stage", GetController().onWebSocketRequestForBackRepoContent) v1.GET("/v1/stacks", GetController().stacks) } } func (controller *Controller) stacks(c *gin.Context) { var res []string for k := range controller.Map_BackRepos { res = append(res, k) } c.JSON(http.StatusOK, res) } // onWebSocketRequestForBackRepoContent is a function that is started each time // a web socket request is received // // 1. upgrade the incomming web connection to a web socket // 1. it subscribe to the backend commit number broadcaster // 1. it stays live and pool for incomming backend commit number broadcast and forward // them on the web socket connection func (controller *Controller) onWebSocketRequestForBackRepoContent(c *gin.Context) { // log.Println("Stack {{PkgPathRoot}}, onWebSocketRequestForBackRepoContent") // Upgrader specifies parameters for upgrading an HTTP connection to a // WebSocket connection. var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { origin := r.Header.Get("Origin") if origin == "" { log.Printf("CheckOrigin: Rejected - Origin header is empty. Request from: %s", r.RemoteAddr) return false // Or handle as per your security policy } u, err := url.Parse(origin) if err != nil { log.Printf("CheckOrigin: Rejected - Invalid Origin URL '%s'. Error: %v", origin, err) return false // Invalid URL } portStr := u.Port() if portStr == "" { // If no port is specified, it might be using default HTTP/HTTPS ports. // For this specific request, we'll assume a port must be present. log.Printf("CheckOrigin: Rejected - No port specified in Origin URL '%s'", origin) return false } port, err := strconv.Atoi(portStr) if err != nil { log.Printf("CheckOrigin: Rejected - Port '%s' in Origin URL '%s' is not a valid number. Error: %v", portStr, origin, err) return false // Port is not a valid number } // Check if the port is 4200 OR in the range 8000-9000 allowed := port == 4200 || (port >= 8000 && port <= 9000) if !allowed { log.Printf("CheckOrigin: Rejected - Port %d from Origin '%s' is not in the allowed list (4200 or 8000-9000)", port, origin) return false } // log.Printf("CheckOrigin: Accepted - Origin '%s' with port %d", origin, port) return true }, } wsConnection, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { fmt.Println(err) return } defer wsConnection.Close() // Create a context that is canceled when the connection is closed ctx, cancel := context.WithCancel(c.Request.Context()) defer cancel() values := c.Request.URL.Query() stackPath := "" if len(values) == 1 { value := values["Name"] if len(value) == 1 { stackPath = value[0] // log.Println("GetLastCommitFromBackNb", "Name", stackPath) } } index := controller.listenerIndex controller.listenerIndex++ backRepo := controller.Map_BackRepos[stackPath] if backRepo == nil { message := "WebSocket Connect, Stack {{PkgPathRoot}}, Unkown stack: \"" + stackPath + "\"\n" message += "Availabe stack names are:\n" for k := range controller.Map_BackRepos { message += k + "\n" } log.Panic(message) } updateCommitBackRepoNbChannel := backRepo.SubscribeToCommitNb(ctx) // Start a goroutine to read from the WebSocket to detect disconnection go func() { for { // ReadMessage is used to detect client disconnection _, _, err := wsConnection.ReadMessage() if err != nil { log.Println("{{PkgPathRoot}}", stackPath, "WS client disconnected:", err) cancel() // Cancel the context return } } }() backRepoData := new(orm.BackRepoData) orm.CopyBackRepoToBackRepoData(backRepo, backRepoData) backRepoData.GONG__Index = index refresh := 0 // Marshal the data to JSON first to be able to get its size jsonData, err := json.Marshal(backRepoData) if err != nil { log.Printf("Error marshaling JSON: %v", err) return } // Get the size of the JSON data in bytes jsonSize := len(jsonData) // Calculate the full SHA-256 hash fullHash := sha256.Sum256(jsonData) // Use the first 12 characters for a shorter, yet highly unique, signature shortHash := hex.EncodeToString(fullHash[:])[0:12] // Use WriteMessage to send the pre-marshaled JSON data. // websocket.TextMessage is typically what WriteJSON uses. err = wsConnection.WriteMessage(websocket.TextMessage, jsonData) if err != nil { log.Println("{{PkgPathRoot}}:\n", "client no longer receiver web socket message, assuming it is no longer alive, closing websocket handler") fmt.Println(err) return } else { // 1. Extract the component name from the long path for cleaner logs // For example, "github.com/fullstack-lang/gong/lib/table/go" becomes "table" parts := strings.Split("{{PkgPathRoot}}", "/") // Assuming goFilePath holds the path component := "unknown" if len(parts) > 2 { component = parts[len(parts)-2] } // 2. Use a single, formatted log line log.Printf( "%-12s | %-85s | Idx: %d | Size: %-9s | Hash: %s", component, stackPath, index, formatBytes(jsonSize), shortHash, ) } for { select { case <-ctx.Done(): // Context canceled, exit the loop return default: for nbCommitBackRepo := range updateCommitBackRepoNbChannel { _ = nbCommitBackRepo refresh += 1 backRepoData := new(orm.BackRepoData) orm.CopyBackRepoToBackRepoData(backRepo, backRepoData) backRepoData.GONG__Index = index // Set write deadline to prevent blocking indefinitely wsConnection.SetWriteDeadline(time.Now().Add(10 * time.Second)) // Send backRepo data // Marshal the data to JSON first to be able to get its size jsonData, err := json.Marshal(backRepoData) if err != nil { log.Printf("Error marshaling JSON: %v", err) return } // Get the size of the JSON data in bytes jsonSize := len(jsonData) // Calculate the full SHA-256 hash fullHash := sha256.Sum256(jsonData) // Use the first 12 characters for a shorter, yet highly unique, signature shortHash := hex.EncodeToString(fullHash[:])[0:12] // Use WriteMessage to send the pre-marshaled JSON data. // websocket.TextMessage is typically what WriteJSON uses. err = wsConnection.WriteMessage(websocket.TextMessage, jsonData) if err != nil { log.Println("{{PkgPathRoot}}:\n", "client no longer receiver web socket message, assuming it is no longer alive, closing websocket handler") fmt.Println(err) return } else { // 1. Extract the component name from the long path for cleaner logs // For example, "github.com/fullstack-lang/gong/lib/table/go" becomes "table" parts := strings.Split("{{PkgPathRoot}}", "/") // Assuming goFilePath holds the path component := "unknown" if len(parts) > 2 { component = parts[len(parts)-2] } // 2. Use a single, formatted log line log.Printf( "%-12s | %-85s | Idx: %d | Size: %-9s | Hash: %s", component, stackPath, index, formatBytes(jsonSize), shortHash, ) } } } } } // formatBytes converts a size in bytes to a human-readable string (KB, MB, GB). func formatBytes(size int) string { if size < 1024 { return fmt.Sprintf("%d B", size) } sizeInKB := float64(size) / 1024.0 if sizeInKB < 1024.0 { // For KB, show one decimal place if it's not a whole number if math.Mod(sizeInKB, 1.0) == 0 { return fmt.Sprintf("%.0f KB", sizeInKB) } return fmt.Sprintf("%.1f KB", sizeInKB) } sizeInMB := sizeInKB / 1024.0 return fmt.Sprintf("%.2f MB", sizeInMB) } // swagger:route GET /commitfrombacknb backrepo GetLastCommitFromBackNb func (controller *Controller) GetLastCommitFromBackNb(c *gin.Context) { values := c.Request.URL.Query() stackPath := "" if len(values) == 1 { value := values["Name"] if len(value) == 1 { stackPath = value[0] // log.Println("GetLastCommitFromBackNb", "Name", stackPath) } } backRepo := controller.Map_BackRepos[stackPath] if backRepo == nil { message := "Stack {{PkgPathRoot}}, Unkown stack: \"" + stackPath + "\"\n" message += "Availabe stack names are:\n" for k := range controller.Map_BackRepos { message += k + "\n" } log.Panic(message) } res := backRepo.GetLastCommitFromBackNb() c.JSON(http.StatusOK, res) } // swagger:route GET /pushfromfrontnb backrepo GetLastPushFromFrontNb func (controller *Controller) GetLastPushFromFrontNb(c *gin.Context) { values := c.Request.URL.Query() stackPath := "" if len(values) == 1 { value := values["Name"] if len(value) == 1 { stackPath = value[0] // log.Println("GetLastPushFromFrontNb", "Name", stackPath) } } backRepo := controller.Map_BackRepos[stackPath] if backRepo == nil { message := "GET Stack {{PkgPathRoot}}, Unkown stack: \"" + stackPath + "\"\n" message += "Availabe stack names are:\n" for k := range controller.Map_BackRepos { message += k + "\n" } log.Panic(message) } res := backRepo.GetLastPushFromFrontNb() c.JSON(http.StatusOK, res) } `
Variables ¶
View Source
var ControllerFileFieldFieldSubTemplateCode map[ControllerFilPerStructSubTemplate]string = map[ControllerFilPerStructSubTemplate]string{ ControllerFileFieldSubTmplGetsBasicFieldBool: ` {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Bool `, ControllerFileFieldSubTmplPostBasicFieldBool: ` {{structname}}DB.{{FieldName}}_Data.Bool = input.{{FieldName}} {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetBasicFieldBool: ` {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Bool `, ControllerFileFieldSubTmplUpdateBasicFieldBool: ` input.{{FieldName}}_Data.Bool = input.{{FieldName}} input.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetsTimeField: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Time } `, ControllerFileFieldSubTmplPostTimeField: ` {{structname}}DB.{{FieldName}}_Data.Time = input.{{FieldName}} {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetTimeField: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Time } `, ControllerFileFieldSubTmplUpdateTimeField: ` input.{{FieldName}}_Data.Time = input.{{FieldName}} input.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetsBasicFieldInt: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{FieldType}}({{structname}}.{{FieldName}}_Data.Int64) } `, ControllerFileFieldSubTmplPostBasicFieldInt: ` {{structname}}DB.{{FieldName}}_Data.Int64 = int64(input.{{FieldName}}) {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetBasicFieldInt: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{FieldType}}({{structname}}.{{FieldName}}_Data.Int64) } `, ControllerFileFieldSubTmplUpdateBasicFieldInt: ` input.{{FieldName}}_Data.Int64 = int64(input.{{FieldName}}) input.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetsBasicFieldFloat64: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Float64 } `, ControllerFileFieldSubTmplPostBasicFieldFloat64: ` {{structname}}DB.{{FieldName}}_Data.Float64 = input.{{FieldName}} {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetBasicFieldFloat64: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.Float64 } `, ControllerFileFieldSubTmplUpdateBasicFieldFloat64: ` input.{{FieldName}}_Data.Float64 = input.{{FieldName}} input.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetsBasicFieldString: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.String } `, ControllerFileFieldSubTmplPostBasicFieldString: ` {{structname}}DB.{{FieldName}}_Data.String = input.{{FieldName}} {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetBasicFieldString: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = {{structname}}.{{FieldName}}_Data.String } `, ControllerFileFieldSubTmplUpdateBasicFieldString: ` input.{{FieldName}}_Data.String = input.{{FieldName}} input.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetsBasicFieldStringEnum: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = models.{{EnumType}}({{structname}}.{{FieldName}}_Data.String) } `, ControllerFileFieldSubTmplPostBasicFieldStringEnum: ` {{structname}}DB.{{FieldName}}_Data.String = string(input.{{FieldName}}) {{structname}}DB.{{FieldName}}_Data.Valid = true `, ControllerFileFieldSubTmplGetBasicFieldStringEnum: ` if {{structname}}.{{FieldName}}_Data.Valid { {{structname}}.{{FieldName}} = models.{{EnumType}}({{structname}}.{{FieldName}}_Data.String) } `, ControllerFileFieldSubTmplUpdateBasicFieldStringEnum: ` input.{{FieldName}}_Data.String = string(input.{{FieldName}}) input.{{FieldName}}_Data.Valid = true `, }
View Source
var ControllersRegistrationsSubTemplate map[string]string = map[string]string{ string(rune(ControllersDeclaration)): ` v1.GET("/v1/{{structname}}s", GetController().Get{{Structname}}s) v1.GET("/v1/{{structname}}s/:id", GetController().Get{{Structname}}) v1.POST("/v1/{{structname}}s", GetController().Post{{Structname}}) v1.PATCH("/v1/{{structname}}s/:id", GetController().Update{{Structname}}) v1.PUT("/v1/{{structname}}s/:id", GetController().Update{{Structname}}) v1.DELETE("/v1/{{structname}}s/:id", GetController().Delete{{Structname}}) `, }
Functions ¶
Types ¶
type ControllerFilPerStructSubTemplate ¶
type ControllerFilPerStructSubTemplate int
Sub Templates
const ( ControllerFileFieldSubTmplGetsBasicFieldBool ControllerFilPerStructSubTemplate = iota ControllerFileFieldSubTmplPostBasicFieldBool ControllerFileFieldSubTmplGetBasicFieldBool ControllerFileFieldSubTmplUpdateBasicFieldBool ControllerFileFieldSubTmplGetsBasicFieldInt ControllerFileFieldSubTmplPostBasicFieldInt ControllerFileFieldSubTmplGetBasicFieldInt ControllerFileFieldSubTmplUpdateBasicFieldInt ControllerFileFieldSubTmplGetsBasicFieldFloat64 ControllerFileFieldSubTmplPostBasicFieldFloat64 ControllerFileFieldSubTmplGetBasicFieldFloat64 ControllerFileFieldSubTmplUpdateBasicFieldFloat64 ControllerFileFieldSubTmplGetsBasicFieldString ControllerFileFieldSubTmplPostBasicFieldString ControllerFileFieldSubTmplGetBasicFieldString ControllerFileFieldSubTmplUpdateBasicFieldString ControllerFileFieldSubTmplGetsTimeField ControllerFileFieldSubTmplPostTimeField ControllerFileFieldSubTmplGetTimeField ControllerFileFieldSubTmplUpdateTimeField ControllerFileFieldSubTmplGetsBasicFieldStringEnum ControllerFileFieldSubTmplPostBasicFieldStringEnum ControllerFileFieldSubTmplGetBasicFieldStringEnum ControllerFileFieldSubTmplUpdateBasicFieldStringEnum )
type ControllerFileInsertionPoint ¶
type ControllerFileInsertionPoint int
insertion points
const ( ControllerFileGetsInsertion ControllerFileInsertionPoint = iota ControllerFilePostInsertion ControllerFileGetInsertion ControllerFileUpdateInsertion ControllerFileNbInsertionPoints )
type ControllersRegistrationsSubTemplateInsertions ¶
type ControllersRegistrationsSubTemplateInsertions int
const (
ControllersDeclaration ControllersRegistrationsSubTemplateInsertions = iota
)
Click to show internal directories.
Click to hide internal directories.