| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 | package streamsimport (	"github.com/0xJacky/Nginx-UI/api"	"github.com/0xJacky/Nginx-UI/internal/config"	"github.com/0xJacky/Nginx-UI/internal/helper"	"github.com/0xJacky/Nginx-UI/internal/nginx"	"github.com/0xJacky/Nginx-UI/query"	"github.com/gin-gonic/gin"	"github.com/sashabaranov/go-openai"	"net/http"	"os"	"strings"	"time")type Stream struct {	ModifiedAt      time.Time                      `json:"modified_at"`	Advanced        bool                           `json:"advanced"`	Enabled         bool                           `json:"enabled"`	Name            string                         `json:"name"`	Config          string                         `json:"config"`	ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`	Tokenized       *nginx.NgxConfig               `json:"tokenized,omitempty"`	Filepath        string                         `json:"filepath"`}func GetStreams(c *gin.Context) {	name := c.Query("name")	orderBy := c.Query("order_by")	sort := c.DefaultQuery("sort", "desc")	configFiles, err := os.ReadDir(nginx.GetConfPath("streams-available"))	if err != nil {		api.ErrHandler(c, err)		return	}	enabledConfig, err := os.ReadDir(nginx.GetConfPath("streams-enabled"))	if err != nil {		api.ErrHandler(c, err)		return	}	enabledConfigMap := make(map[string]bool)	for i := range enabledConfig {		enabledConfigMap[enabledConfig[i].Name()] = true	}	var configs []config.Config	for i := range configFiles {		file := configFiles[i]		fileInfo, _ := file.Info()		if !file.IsDir() {			if name != "" && !strings.Contains(file.Name(), name) {				continue			}			configs = append(configs, config.Config{				Name:       file.Name(),				ModifiedAt: fileInfo.ModTime(),				Size:       fileInfo.Size(),				IsDir:      fileInfo.IsDir(),				Enabled:    enabledConfigMap[file.Name()],			})		}	}	configs = config.Sort(orderBy, sort, configs)	c.JSON(http.StatusOK, gin.H{		"data": configs,	})}func GetStream(c *gin.Context) {	rewriteName, ok := c.Get("rewriteConfigFileName")	name := c.Param("name")	// for modify filename	if ok {		name = rewriteName.(string)	}	path := nginx.GetConfPath("streams-available", name)	file, err := os.Stat(path)	if os.IsNotExist(err) {		c.JSON(http.StatusNotFound, gin.H{			"message": "file not found",		})		return	}	enabled := true	if _, err := os.Stat(nginx.GetConfPath("streams-enabled", name)); os.IsNotExist(err) {		enabled = false	}	g := query.ChatGPTLog	chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()	if err != nil {		api.ErrHandler(c, err)		return	}	if chatgpt.Content == nil {		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)	}	s := query.Stream	stream, err := s.Where(s.Path.Eq(path)).FirstOrInit()	if err != nil {		api.ErrHandler(c, err)		return	}	if stream.Advanced {		origContent, err := os.ReadFile(path)		if err != nil {			api.ErrHandler(c, err)			return		}		c.JSON(http.StatusOK, Stream{			ModifiedAt:      file.ModTime(),			Advanced:        stream.Advanced,			Enabled:         enabled,			Name:            name,			Config:          string(origContent),			ChatGPTMessages: chatgpt.Content,			Filepath:        path,		})		return	}	nginxConfig, err := nginx.ParseNgxConfig(path)	if err != nil {		api.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, Stream{		ModifiedAt:      file.ModTime(),		Advanced:        stream.Advanced,		Enabled:         enabled,		Name:            name,		Config:          nginxConfig.FmtCode(),		Tokenized:       nginxConfig,		ChatGPTMessages: chatgpt.Content,		Filepath:        path,	})}func SaveStream(c *gin.Context) {	name := c.Param("name")	if name == "" {		c.JSON(http.StatusNotAcceptable, gin.H{			"message": "param name is empty",		})		return	}	var json struct {		Name      string `json:"name" binding:"required"`		Content   string `json:"content" binding:"required"`		Overwrite bool   `json:"overwrite"`	}	if !api.BindAndValid(c, &json) {		return	}	path := nginx.GetConfPath("streams-available", name)	if !json.Overwrite && helper.FileExists(path) {		c.JSON(http.StatusNotAcceptable, gin.H{			"message": "File exists",		})		return	}	err := os.WriteFile(path, []byte(json.Content), 0644)	if err != nil {		api.ErrHandler(c, err)		return	}	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", name)	// rename the config file if needed	if name != json.Name {		newPath := nginx.GetConfPath("streams-available", json.Name)		s := query.Stream		_, err = s.Where(s.Path.Eq(path)).Update(s.Path, newPath)		// check if dst file exists, do not rename		if helper.FileExists(newPath) {			c.JSON(http.StatusNotAcceptable, gin.H{				"message": "File exists",			})			return		}		// recreate a soft link		if helper.FileExists(enabledConfigFilePath) {			_ = os.Remove(enabledConfigFilePath)			enabledConfigFilePath = nginx.GetConfPath("streams-enabled", json.Name)			err = os.Symlink(newPath, enabledConfigFilePath)			if err != nil {				api.ErrHandler(c, err)				return			}		}		err = os.Rename(path, newPath)		if err != nil {			api.ErrHandler(c, err)			return		}		name = json.Name		c.Set("rewriteConfigFileName", name)	}	enabledConfigFilePath = nginx.GetConfPath("streams-enabled", name)	if helper.FileExists(enabledConfigFilePath) {		// Test nginx configuration		output := nginx.TestConf()		if nginx.GetLogLevel(output) > nginx.Warn {			c.JSON(http.StatusInternalServerError, gin.H{				"message": output,			})			return		}		output = nginx.Reload()		if nginx.GetLogLevel(output) > nginx.Warn {			c.JSON(http.StatusInternalServerError, gin.H{				"message": output,			})			return		}	}	GetStream(c)}func EnableStream(c *gin.Context) {	configFilePath := nginx.GetConfPath("streams-available", c.Param("name"))	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", c.Param("name"))	_, err := os.Stat(configFilePath)	if err != nil {		api.ErrHandler(c, err)		return	}	if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {		err = os.Symlink(configFilePath, enabledConfigFilePath)		if err != nil {			api.ErrHandler(c, err)			return		}	}	// Test nginx config, if not pass, then disable the stream.	output := nginx.TestConf()	if nginx.GetLogLevel(output) > nginx.Warn {		_ = os.Remove(enabledConfigFilePath)		c.JSON(http.StatusInternalServerError, gin.H{			"message": output,		})		return	}	output = nginx.Reload()	if nginx.GetLogLevel(output) > nginx.Warn {		c.JSON(http.StatusInternalServerError, gin.H{			"message": output,		})		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func DisableStream(c *gin.Context) {	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", c.Param("name"))	_, err := os.Stat(enabledConfigFilePath)	if err != nil {		api.ErrHandler(c, err)		return	}	err = os.Remove(enabledConfigFilePath)	if err != nil {		api.ErrHandler(c, err)		return	}	output := nginx.Reload()	if nginx.GetLogLevel(output) > nginx.Warn {		c.JSON(http.StatusInternalServerError, gin.H{			"message": output,		})		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func DeleteStream(c *gin.Context) {	var err error	name := c.Param("name")	availablePath := nginx.GetConfPath("streams-available", name)	enabledPath := nginx.GetConfPath("streams-enabled", name)	if _, err = os.Stat(availablePath); os.IsNotExist(err) {		c.JSON(http.StatusNotFound, gin.H{			"message": "stream not found",		})		return	}	if _, err = os.Stat(enabledPath); err == nil {		c.JSON(http.StatusNotAcceptable, gin.H{			"message": "stream is enabled",		})		return	}	if err = os.Remove(availablePath); err != nil {		api.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}
 |