github.com/weplanx/server@v0.2.6-0.20240318110640-f7e75155779a/api/api.go (about)

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/cloudwego/hertz/pkg/app"
     7  	"github.com/cloudwego/hertz/pkg/app/server"
     8  	"github.com/cloudwego/hertz/pkg/common/hlog"
     9  	"github.com/cloudwego/hertz/pkg/common/utils"
    10  	"github.com/google/wire"
    11  	"github.com/nats-io/nats.go"
    12  	transfer "github.com/weplanx/collector/client"
    13  	"github.com/weplanx/go/csrf"
    14  	"github.com/weplanx/go/passport"
    15  	"github.com/weplanx/go/rest"
    16  	"github.com/weplanx/go/sessions"
    17  	"github.com/weplanx/go/values"
    18  	"github.com/weplanx/server/api/acc_tasks"
    19  	"github.com/weplanx/server/api/builders"
    20  	"github.com/weplanx/server/api/clusters"
    21  	"github.com/weplanx/server/api/datasets"
    22  	"github.com/weplanx/server/api/endpoints"
    23  	"github.com/weplanx/server/api/imessages"
    24  	"github.com/weplanx/server/api/index"
    25  	"github.com/weplanx/server/api/lark"
    26  	"github.com/weplanx/server/api/monitor"
    27  	"github.com/weplanx/server/api/projects"
    28  	"github.com/weplanx/server/api/queues"
    29  	"github.com/weplanx/server/api/tencent"
    30  	"github.com/weplanx/server/api/workflows"
    31  	"github.com/weplanx/server/common"
    32  	"time"
    33  )
    34  
    35  var Provides = wire.NewSet(
    36  	wire.Struct(new(values.Controller), "*"),
    37  	wire.Struct(new(sessions.Controller), "*"),
    38  	wire.Struct(new(rest.Controller), "*"),
    39  	index.Provides,
    40  	tencent.Provides,
    41  	lark.Provides,
    42  	projects.Provides,
    43  	clusters.Provides,
    44  	endpoints.Provides,
    45  	acc_tasks.Provides,
    46  	datasets.Provides,
    47  	monitor.Provides,
    48  	imessages.Provides,
    49  	queues.Provides,
    50  	workflows.Provides,
    51  	builders.Provides,
    52  )
    53  
    54  type API struct {
    55  	*common.Inject
    56  
    57  	Hertz      *server.Hertz
    58  	Csrf       *csrf.Csrf
    59  	Values     *values.Controller
    60  	Sessions   *sessions.Controller
    61  	Rest       *rest.Controller
    62  	Index      *index.Controller
    63  	IndexX     *index.Service
    64  	Tencent    *tencent.Controller
    65  	TencentX   *tencent.Service
    66  	Lark       *lark.Controller
    67  	LarkX      *lark.Service
    68  	Projects   *projects.Controller
    69  	ProjectsX  *projects.Service
    70  	Clusters   *clusters.Controller
    71  	ClustersX  *clusters.Service
    72  	Endpoints  *endpoints.Controller
    73  	EndpointsX *endpoints.Service
    74  	Workflows  *workflows.Controller
    75  	WorkflowsX *workflows.Service
    76  	Queues     *queues.Controller
    77  	QueuesX    *queues.Service
    78  	Imessages  *imessages.Controller
    79  	ImessagesX *imessages.Service
    80  	AccTasks   *acc_tasks.Controller
    81  	AccTasksX  *acc_tasks.Service
    82  	Datasets   *datasets.Controller
    83  	DatasetsX  *datasets.Service
    84  	Monitor    *monitor.Controller
    85  	MonitorX   *monitor.Service
    86  	Builders   *builders.Controller
    87  	BuildersX  *builders.Service
    88  }
    89  
    90  func (x *API) Routes(h *server.Hertz) (err error) {
    91  	csrfToken := x.Csrf.VerifyToken(!x.V.IsRelease())
    92  	auth := x.AuthGuard()
    93  	audit := x.Audit()
    94  
    95  	h.GET("", x.Index.Ping)
    96  	_login := h.Group("login", csrfToken)
    97  	{
    98  		_login.POST("", x.Index.Login)
    99  		_login.GET("sms", x.Index.GetLoginSms)
   100  		_login.POST("sms", x.Index.LoginSms)
   101  		_login.POST("totp", x.Index.LoginTotp)
   102  	}
   103  	h.GET("forget_code", x.Index.GetForgetCode)
   104  	h.POST("forget_reset", csrfToken, x.Index.ForgetReset)
   105  	h.GET("verify", csrfToken, x.Index.Verify)
   106  	h.GET("refresh_code", csrfToken, auth, x.Index.GetRefreshCode)
   107  	h.POST("refresh_token", csrfToken, auth, x.Index.RefreshToken)
   108  	h.POST("logout", csrfToken, auth, x.Index.Logout)
   109  	h.GET("options", x.Index.Options)
   110  
   111  	m := []app.HandlerFunc{csrfToken, auth, audit}
   112  	_user := h.Group("user", m...)
   113  	{
   114  		_user.GET("", x.Index.GetUser)
   115  		_user.PATCH("", x.Index.SetUser)
   116  		_user.POST("password", x.Index.SetUserPassword)
   117  		_user.GET("phone_code", x.Index.GetUserPhoneCode)
   118  		_user.POST("phone", x.Index.SetUserPhone)
   119  		_user.GET("totp", x.Index.GetUserTotp)
   120  		_user.POST("totp", x.Index.SetUserTotp)
   121  		_user.DELETE(":key", x.Index.UnsetUser)
   122  	}
   123  	_values := h.Group("values", m...)
   124  	{
   125  		_values.GET("", x.Values.Get)
   126  		_values.PATCH("", x.Values.Set)
   127  		_values.DELETE(":key", x.Values.Remove)
   128  	}
   129  	_sessions := h.Group("sessions", m...)
   130  	{
   131  		_sessions.GET("", x.Sessions.Lists)
   132  		_sessions.DELETE(":uid", x.Sessions.Remove)
   133  		_sessions.POST("clear", x.Sessions.Clear)
   134  	}
   135  	_db := h.Group("db", csrfToken, auth)
   136  	{
   137  		_db.GET(":collection/:id", x.Rest.FindById)
   138  		_db.POST(":collection/create", audit, x.Rest.Create)
   139  		_db.POST(":collection/bulk_create", audit, x.Rest.BulkCreate)
   140  		_db.POST(":collection/size", x.Rest.Size)
   141  		_db.POST(":collection/find", x.Rest.Find)
   142  		_db.POST(":collection/find_one", x.Rest.FindOne)
   143  		_db.POST(":collection/update", audit, x.Rest.Update)
   144  		_db.POST(":collection/bulk_delete", audit, x.Rest.BulkDelete)
   145  		_db.POST(":collection/sort", audit, x.Rest.Sort)
   146  		_db.PATCH(":collection/:id", audit, x.Rest.UpdateById)
   147  		_db.PUT(":collection/:id", audit, x.Rest.Replace)
   148  		_db.DELETE(":collection/:id", audit, x.Rest.Delete)
   149  		_db.POST("transaction", audit, x.Rest.Transaction)
   150  		_db.POST("commit", audit, x.Rest.Commit)
   151  	}
   152  	_tencent := h.Group("tencent", m...)
   153  	{
   154  		_tencent.GET("cos_presigned", x.Tencent.CosPresigned)
   155  		_tencent.GET("cos_image_info", x.Tencent.CosImageInfo)
   156  	}
   157  	h.POST("lark", x.Lark.Challenge)
   158  	h.GET("lark", x.Lark.OAuth)
   159  	_lark := h.Group("lark", m...)
   160  	{
   161  		_lark.POST("tasks", x.Lark.CreateTasks)
   162  		_lark.GET("tasks", x.Lark.GetTasks)
   163  	}
   164  	_projects := h.Group("projects", m...)
   165  	{
   166  		_projects.GET(":id/tenants", x.Projects.GetTenants)
   167  		_projects.POST("deploy_nats", x.Projects.DeployNats)
   168  	}
   169  	_clusters := h.Group("clusters", m...)
   170  	{
   171  		_clusters.GET(":id/info", x.Clusters.GetInfo)
   172  		_clusters.GET(":id/nodes", x.Clusters.GetNodes)
   173  	}
   174  	_endpoints := h.Group("endpoints", m...)
   175  	{
   176  		_endpoints.GET(":id/schedule_keys", x.Endpoints.ScheduleKeys)
   177  		_endpoints.POST("schedule_ping", x.Endpoints.SchedulePing)
   178  		_endpoints.POST("schedule_revoke", x.Endpoints.ScheduleRevoke)
   179  		_endpoints.POST("schedule_state", x.Endpoints.ScheduleState)
   180  	}
   181  	_workflows := h.Group("workflows", m...)
   182  	{
   183  		_workflows.POST("sync", x.Workflows.Sync)
   184  	}
   185  	_queues := h.Group("queues", m...)
   186  	{
   187  		_queues.POST("sync", x.Queues.Sync)
   188  		_queues.GET(":id/info", x.Queues.Info)
   189  		_queues.POST("publish", x.Queues.Publish)
   190  	}
   191  	_builders := h.Group("builders", m...)
   192  	{
   193  		_builders.POST("sort_fields", x.Builders.SortFields)
   194  	}
   195  	_imessages := h.Group("imessages", m...)
   196  	{
   197  		_imessages.GET("nodes", x.Imessages.GetNodes)
   198  		_imessages.PUT(":id/rule", x.Imessages.UpdateRule)
   199  		_imessages.DELETE(":id/rule", x.Imessages.DeleteRule)
   200  		_imessages.GET(":id/metrics", x.Imessages.GetMetrics)
   201  		_imessages.PUT(":id/metrics", x.Imessages.UpdateMetrics)
   202  		_imessages.DELETE(":id/metrics", x.Imessages.DeleteMetrics)
   203  		_imessages.POST("publish", x.Imessages.Publish)
   204  	}
   205  	_accTasks := h.Group("acc_tasks", m...)
   206  	{
   207  		_accTasks.POST("invoke", x.AccTasks.Invoke)
   208  	}
   209  	_datasets := h.Group("datasets", m...)
   210  	{
   211  		_datasets.GET("", x.Datasets.Lists)
   212  		_datasets.POST("create", x.Datasets.Create)
   213  		_datasets.DELETE(":name", x.Datasets.Delete)
   214  	}
   215  	if *x.V.Influx.Enabled {
   216  		_monitor := h.Group("monitor", m...)
   217  		{
   218  			_monitor.GET(":name", x.Monitor.Exporters)
   219  		}
   220  	}
   221  	return
   222  }
   223  
   224  func (x *API) AuthGuard() app.HandlerFunc {
   225  	return func(ctx context.Context, c *app.RequestContext) {
   226  		ts := c.Cookie("TOKEN")
   227  		if ts == nil {
   228  			c.AbortWithStatusJSON(401, utils.H{
   229  				"code":    0,
   230  				"message": "authentication has expired, please log in again",
   231  			})
   232  			return
   233  		}
   234  
   235  		claims, err := x.IndexX.Verify(ctx, string(ts))
   236  		if err != nil {
   237  			common.ClearAccessToken(c)
   238  			c.AbortWithStatusJSON(401, utils.H{
   239  				"code":    0,
   240  				"message": common.ErrAuthenticationExpired.Error(),
   241  			})
   242  			return
   243  		}
   244  
   245  		c.Set("identity", claims)
   246  		c.Next(ctx)
   247  	}
   248  }
   249  
   250  func (x *API) Audit() app.HandlerFunc {
   251  	return func(ctx context.Context, c *app.RequestContext) {
   252  		now := time.Now()
   253  		c.Next(ctx)
   254  		method := string(c.Request.Header.Method())
   255  		if method == "GET" {
   256  			return
   257  		}
   258  		var userId string
   259  		if value, ok := c.Get("identity"); ok {
   260  			claims := value.(passport.Claims)
   261  			userId = claims.UserId
   262  		}
   263  
   264  		format := map[string]interface{}{
   265  			"body": "json",
   266  		}
   267  		if userId != "" {
   268  			format["metadata.user_id"] = "oid"
   269  		}
   270  		transferCtx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   271  		defer cancel()
   272  
   273  		x.Transfer.Publish(transferCtx, "logset_operates", transfer.Payload{
   274  			Timestamp: now,
   275  			Data: map[string]interface{}{
   276  				"metadata": map[string]interface{}{
   277  					"method":    method,
   278  					"path":      string(c.Request.Path()),
   279  					"user_id":   userId,
   280  					"client_ip": c.ClientIP(),
   281  				},
   282  				"params": string(c.Request.QueryString()),
   283  				"body":   c.Request.Body(),
   284  				"status": c.Response.StatusCode(),
   285  			},
   286  			XData: format,
   287  		})
   288  	}
   289  }
   290  
   291  func (x *API) Initialize(ctx context.Context) (h *server.Hertz, err error) {
   292  	h = x.Hertz
   293  
   294  	update := make(chan interface{})
   295  	go x.Values.Service.Sync(x.V.Extra, update)
   296  	go x.ValuesChange(update)
   297  
   298  	if err = x.Transfer.Set(ctx, transfer.StreamOption{
   299  		Key: "logset_operates",
   300  	}); err != nil {
   301  		return
   302  	}
   303  
   304  	go func() {
   305  		if err = x.WorkflowsX.Event(); err != nil {
   306  			hlog.Error(err)
   307  		}
   308  		if err = x.QueuesX.Event(); err != nil {
   309  			hlog.Error(err)
   310  		}
   311  		if err = x.ImessagesX.Event(); err != nil {
   312  			hlog.Error(err)
   313  		}
   314  	}()
   315  
   316  	return
   317  }
   318  
   319  func (x *API) ValuesChange(ok chan interface{}) {
   320  	for range ok {
   321  		for k, v := range x.V.RestControls {
   322  			if v.Event {
   323  				if _, err := x.JetStream.AddStream(&nats.StreamConfig{
   324  					Name:      fmt.Sprintf(`EVENT_%s`, k),
   325  					Subjects:  []string{fmt.Sprintf(`events.%s`, k)},
   326  					Retention: nats.WorkQueuePolicy,
   327  				}); err != nil {
   328  					hlog.Error(err)
   329  				}
   330  			}
   331  		}
   332  	}
   333  	return
   334  }