package handler import ( "encoding/json" "houston/common/util" "houston/internal/cron" "houston/internal/diagnostic" "houston/internal/processor" "houston/internal/resolver" "houston/model/incident" "houston/model/log" "houston/model/severity" "houston/model/shedlock" "houston/model/tag" "houston/model/team" "houston/model/user" "houston/pkg/rest" "houston/pkg/slackbot" rcaRepository "houston/repository/rca/impl" "houston/repository/rcaInput" "houston/service/documentService" incidentServiceV2 "houston/service/incident" "houston/service/rca" 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" logger "houston/logger" ) type slackHandler struct { socketModeClient *socketmode.Client slashCommandProcessor *processor.SlashCommandProcessor memberJoinCallbackProcessor *processor.MemberJoinedCallbackEventProcessor blockActionProcessor *processor.BlockActionProcessor viewSubmissionProcessor *processor.ViewSubmissionProcessor slashCommandResolver *resolver.SlashCommandResolver diagnosticCommandProcessor *processor.DiagnosticCommandProcessor userChangeEventProcessor *processor.UserChangeEventProcessor } func NewSlackHandler(gormClient *gorm.DB, socketModeClient *socketmode.Client) *slackHandler { severityService := severity.NewSeverityRepository(gormClient) logRepository := log.NewLogRepository(gormClient) tagService := tag.NewTagRepository(gormClient) teamService := team.NewTeamRepository(gormClient, logRepository) incidentService := incident.NewIncidentRepository(gormClient, severityService, logRepository, teamService, socketModeClient) userService := user.NewUserRepository(gormClient) shedlockService := shedlock.NewShedlockRepository(gormClient) slackbotClient := slackbot.NewSlackClient(socketModeClient) slashCommandProcessor := processor.NewSlashCommandProcessor(socketModeClient, incidentService, slackbotClient) grafanaRepository := diagnostic.NewDiagnoseRepository(gormClient) diagnosticCommandProcessor := processor.NewDiagnosticCommandProcessor(socketModeClient, grafanaRepository) incidentServiceV2 := incidentServiceV2.NewIncidentServiceV2(gormClient) slackService := slack2.NewSlackService() // new services rcaRepository := rcaRepository.NewRcaRepository(gormClient) rcaInputRepository := rcaInput.NewRcaInputRepository(gormClient) restClient := rest.NewClientActionsImpl() documentService := documentService.NewActionsImpl(restClient) rcaService := rca.NewRcaService(incidentServiceV2, slackService, restClient, documentService, rcaRepository, rcaInputRepository, userService) cron.RunJob( socketModeClient, gormClient, incidentService, severityService, teamService, shedlockService, userService, incidentServiceV2, slackService, ) return &slackHandler{ socketModeClient: socketModeClient, slashCommandProcessor: slashCommandProcessor, diagnosticCommandProcessor: diagnosticCommandProcessor, memberJoinCallbackProcessor: processor.NewMemberJoinedCallbackEventProcessor( socketModeClient, incidentService, teamService, severityService, ), blockActionProcessor: processor.NewBlockActionProcessor( socketModeClient, incidentService, teamService, severityService, tagService, slackbotClient, incidentServiceV2, slackService, rcaService, ), viewSubmissionProcessor: processor.NewViewSubmissionProcessor( socketModeClient, incidentService, teamService, severityService, tagService, teamService, slackbotClient, gormClient, ), slashCommandResolver: resolver.NewSlashCommandResolver( diagnosticCommandProcessor, slashCommandProcessor, ), userChangeEventProcessor: processor.NewUserChangeEventProcessor( socketModeClient, userService, ), } } func (sh *slackHandler) HoustonConnect() { go func() { for evt := range sh.socketModeClient.Events { 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: sh.userChangeEventProcessor.ProcessCommand(ev, evt.Request) } switch innerEventData := innerEvent.Data.(type) { case *slackevents.MemberJoinedChannelEvent: sh.memberJoinCallbackProcessor.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.String("request", string(serializedRequestJson))) } sh.viewSubmissionProcessor.ProcessCommand(callback, evt.Request) } } } case socketmode.EventTypeSlashCommand: { sh.slashCommandResolver.Resolve(&evt) } default: { logger.Error("houston unexpected event type received", zap.String("event_type", string(evt.Type))) } } } }() go sh.socketModeClient.Run() }