Files
houston-be/cmd/app/handler/slack_handler.go
2025-05-26 17:29:41 +05:30

229 lines
8.1 KiB
Go

package handler
import (
"encoding/json"
"fmt"
"houston/appcontext"
"houston/common/metrics"
"houston/common/util"
"houston/internal/processor"
"houston/internal/resolver"
"houston/model/incident"
"houston/model/log"
"houston/model/team"
"houston/model/user"
"houston/pkg/rest"
"houston/pkg/slackbot"
rcaRepository "houston/repository/rca/impl"
"houston/repository/rcaInput"
"houston/repository/severity"
"houston/repository/tag"
"houston/service/documentService"
incidentServiceV2 "houston/service/incident/impl"
"houston/service/orchestration"
rcaService "houston/service/rca/impl"
slack2 "houston/service/slack"
"github.com/slack-go/slack"
"github.com/slack-go/slack/slackevents"
"github.com/slack-go/slack/socketmode"
"github.com/spf13/viper"
"go.uber.org/zap"
"gorm.io/gorm"
"houston/logger"
)
type slackHandler struct {
socketModeClient *socketmode.Client
slashCommandProcessor *processor.SlashCommandProcessor
commandProcessor processor.CommandProcessor
memberJoinCallbackProcessor *processor.MemberJoinedCallbackEventProcessor
channelUnarchivalEventProcessor *processor.ChannelUnarchivalEventProcessor
blockActionProcessor *processor.BlockActionProcessor
viewSubmissionProcessor *processor.ViewSubmissionProcessor
userChangeEventProcessor *processor.UserChangeEventProcessor
houstonCommandResolver *resolver.HoustonCommandResolver
memberLeftChannelEventProcessor *processor.MemberLeftChannelCallbackEventProcessor
}
func NewSlackHandler(
gormClient *gorm.DB, socketModeClient *socketmode.Client, orchestrator orchestration.IncidentOrchestrator,
) *slackHandler {
severityService := severity.NewSeverityRepository(gormClient)
logRepository := log.NewLogRepository(gormClient)
tagService := tag.NewTagRepository(gormClient)
teamService := team.NewTeamRepository(gormClient, logRepository)
incidentService := incident.NewIncidentRepository(
gormClient, appcontext.GetSeverityService(), appcontext.GetIncidentStatusService(),
logRepository, teamService, socketModeClient,
)
productsService := appcontext.GetProductsService()
userService := user.NewUserRepository(gormClient)
slackbotClient := slackbot.NewSlackClient(socketModeClient)
incidentServiceV2 := incidentServiceV2.NewIncidentServiceV2(gormClient)
slackService := slack2.NewSlackService()
// new services
rcaRepository := rcaRepository.NewRcaRepository(gormClient)
rcaInputRepository := rcaInput.NewRcaInputRepository(gormClient)
restClient := rest.NewHttpRestClient()
documentService := documentService.NewActionsImpl(restClient)
rcaService := rcaService.NewRcaService(
incidentServiceV2, slackService, documentService, rcaRepository,
rcaInputRepository, userService, appcontext.GetDriveService(), appcontext.GetIncidentJiraService(),
)
productTeamService := appcontext.GetProductTeamsService()
slashCommandProcessor := processor.NewSlashCommandProcessor(socketModeClient, slackbotClient, rcaService)
tagValueService := appcontext.GetTagValueService()
return &slackHandler{
socketModeClient: socketModeClient,
slashCommandProcessor: slashCommandProcessor,
memberJoinCallbackProcessor: processor.NewMemberJoinedCallbackEventProcessor(
socketModeClient, incidentService, teamService, severityService,
),
channelUnarchivalEventProcessor: processor.NewChannelUnarchivalEventProcessor(),
blockActionProcessor: processor.NewBlockActionProcessor(
socketModeClient,
incidentService,
teamService,
severityService,
tagService,
slackbotClient,
incidentServiceV2,
slackService, rcaService,
productsService,
productTeamService,
orchestrator,
tagValueService,
),
viewSubmissionProcessor: processor.NewViewSubmissionProcessor(
socketModeClient,
incidentService,
productsService,
productTeamService,
teamService,
severityService,
tagService,
teamService,
slackbotClient,
gormClient,
rcaService,
incidentServiceV2,
orchestrator,
tagValueService,
),
userChangeEventProcessor: processor.NewUserChangeEventProcessor(
socketModeClient, userService,
),
houstonCommandResolver: resolver.NewHoustonCommandResolver(
socketModeClient, slackbotClient, rcaService, productsService, orchestrator, tagValueService,
),
memberLeftChannelEventProcessor: processor.NewMemberLeftChannelCallbackEventProcessor(socketModeClient, *incidentServiceV2, appcontext.GetUserService()),
}
}
func (sh *slackHandler) HoustonConnect() {
go func() {
for evt := range sh.socketModeClient.Events {
metrics.PublishWebSocketEventMetrics(string(evt.Type))
switch evt.Type {
case socketmode.EventTypeConnecting:
{
logger.Info("houston connecting to slackbot with socket mode")
}
case socketmode.EventTypeConnectionError:
{
logger.Error("appToken : " + viper.GetString("houston.slack.app.token"))
logger.Error("botToken : " + viper.GetString("houston.slack.bot.token"))
logger.Error("houston connection failed.")
}
case socketmode.EventTypeConnected:
{
logger.Info("houston connected to slackbot with socket mode")
}
case socketmode.EventTypeEventsAPI:
{
ev, _ := evt.Data.(slackevents.EventsAPIEvent)
eventJson := &ev
serializedEventJson, eventErr := json.Marshal(eventJson)
if eventErr != nil {
logger.Error("error occurred while serializing the event object", zap.Any("error", eventErr))
} else {
if ev.InnerEvent.Type != util.UserChangeEvent {
logger.Info("event api", zap.String("event", string(serializedEventJson)))
}
}
switch ev.Type {
case slackevents.CallbackEvent:
innerEvent := ev.InnerEvent
switch innerEvent.Type {
case util.UserChangeEvent:
logger.Info(fmt.Sprintf("[UserChangeEvent-socket] received user change event: %v and Type: %s", ev.InnerEvent.Data, ev.InnerEvent.Type))
sh.userChangeEventProcessor.ProcessCommand(ev, evt.Request)
case util.ChannelUnarchiveEvent:
sh.channelUnarchivalEventProcessor.ProcessCommand(
innerEvent.Data.(*slackevents.ChannelUnarchiveEvent), *evt.Request, sh.socketModeClient,
)
}
switch innerEventData := innerEvent.Data.(type) {
case *slackevents.MemberJoinedChannelEvent:
sh.memberJoinCallbackProcessor.ProcessCommand(innerEventData, evt.Request)
case *slackevents.MemberLeftChannelEvent:
sh.memberLeftChannelEventProcessor.ProcessCommand(innerEventData, evt.Request)
}
}
}
case socketmode.EventTypeInteractive:
{
callback, _ := evt.Data.(slack.InteractionCallback)
switch callback.Type {
case slack.InteractionTypeBlockActions:
{
logger.Info(
"received interaction type block action",
zap.String("action_id", callback.ActionID), zap.String("block_id", callback.BlockID),
)
sh.blockActionProcessor.ProcessCommand(callback, evt.Request)
}
case slack.InteractionTypeViewSubmission:
{
logger.Info(
"received interaction type view submission",
zap.String("action_id", callback.ActionID), zap.String("block_id", callback.BlockID),
)
callbackJson := &callback
serializedCallbackJson, callbackErr := json.Marshal(callbackJson)
if callbackErr != nil {
logger.Error("error occurred while serializing the callback object", zap.Any("error", callbackErr))
} else {
logger.Info("callback data", zap.String("callback", string(serializedCallbackJson)))
}
requestJson := &evt.Request
serializedRequestJson, requestErr := json.Marshal(requestJson)
if requestErr != nil {
logger.Error("error occurred while serializing the request object", zap.Any("error", requestErr))
} else {
logger.Info("request data", zap.Any("request", serializedRequestJson))
}
sh.viewSubmissionProcessor.ProcessCommand(callback, evt.Request)
}
}
}
case socketmode.EventTypeSlashCommand:
{
sh.houstonCommandResolver.Resolve(&evt).ProcessSlashCommand(&evt)
}
default:
{
logger.Error("houston unexpected event type received", zap.String("event_type", string(evt.Type)))
}
}
}
}()
go sh.socketModeClient.Run()
}