Add slack message retrieval
This commit is contained in:
parent
c9961d6cd8
commit
555184a033
4
TODO.md
4
TODO.md
@ -15,7 +15,3 @@ Examples:
|
||||
- https://github.com/nsf/godit
|
||||
- https://github.com/moncho/dry
|
||||
- https://github.com/mikepea/go-jira-ui
|
||||
|
||||
- [ ] show cursor, see if you can alter Par
|
||||
- [ ] input overflow
|
||||
- [ ] chat
|
||||
|
56
src/components/channels.go
Normal file
56
src/components/channels.go
Normal file
@ -0,0 +1,56 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"github.com/erroneousboat/slack-term/src/service"
|
||||
"github.com/gizak/termui"
|
||||
)
|
||||
|
||||
type Channels struct {
|
||||
List *termui.List
|
||||
}
|
||||
|
||||
func CreateChannels(svc *service.SlackService, inputHeight int) *Channels {
|
||||
channels := &Channels{
|
||||
List: termui.NewList(),
|
||||
}
|
||||
|
||||
channels.List.BorderLabel = "Channels"
|
||||
channels.List.Overflow = "wrap"
|
||||
channels.List.Height = termui.TermHeight() - inputHeight
|
||||
|
||||
channels.GetChannels(svc)
|
||||
|
||||
return channels
|
||||
}
|
||||
|
||||
// Buffer implements interface termui.Bufferer
|
||||
func (c *Channels) Buffer() termui.Buffer {
|
||||
buf := c.List.Buffer()
|
||||
return buf
|
||||
}
|
||||
|
||||
// GetHeight implements interface termui.GridBufferer
|
||||
func (c *Channels) GetHeight() int {
|
||||
return c.List.Block.GetHeight()
|
||||
}
|
||||
|
||||
// SetWidth implements interface termui.GridBufferer
|
||||
func (c *Channels) SetWidth(w int) {
|
||||
c.List.SetWidth(w)
|
||||
}
|
||||
|
||||
// SetX implements interface termui.GridBufferer
|
||||
func (c *Channels) SetX(x int) {
|
||||
c.List.SetX(x)
|
||||
}
|
||||
|
||||
// SetY implements interface termui.GridBufferer
|
||||
func (c *Channels) SetY(y int) {
|
||||
c.List.SetY(y)
|
||||
}
|
||||
|
||||
func (c *Channels) GetChannels(svc *service.SlackService) {
|
||||
for _, slackChan := range svc.GetChannels() {
|
||||
c.List.Items = append(c.List.Items, slackChan.Name)
|
||||
}
|
||||
}
|
@ -3,21 +3,26 @@ package components
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/erroneousboat/slack-term/src/service"
|
||||
"github.com/gizak/termui"
|
||||
)
|
||||
|
||||
type Chat struct {
|
||||
List *termui.List
|
||||
List *termui.List
|
||||
SelectedChannel string
|
||||
}
|
||||
|
||||
func CreateChat(inputHeight int) *Chat {
|
||||
func CreateChat(svc *service.SlackService, inputHeight int) *Chat {
|
||||
chat := &Chat{
|
||||
List: termui.NewList(),
|
||||
}
|
||||
|
||||
// TODO: should be SetSelectedChannel
|
||||
chat.SelectedChannel = svc.GetChannels()[0].ID
|
||||
|
||||
chat.List.Height = termui.TermHeight() - inputHeight
|
||||
chat.List.Overflow = "wrap"
|
||||
chat.LoadMessages()
|
||||
chat.GetMessages(svc)
|
||||
|
||||
return chat
|
||||
}
|
||||
@ -125,18 +130,15 @@ func (c *Chat) SetY(y int) {
|
||||
c.List.SetY(y)
|
||||
}
|
||||
|
||||
func (c *Chat) LoadMessages() {
|
||||
messages := []string{
|
||||
"[jp] hello world",
|
||||
"[erroneousboat] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar",
|
||||
}
|
||||
func (c *Chat) GetMessages(svc *service.SlackService) {
|
||||
messages := svc.GetMessages(c.SelectedChannel)
|
||||
|
||||
for _, message := range messages {
|
||||
c.AddMessages(message)
|
||||
c.AddMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chat) AddMessages(message string) {
|
||||
func (c *Chat) AddMessage(message string) {
|
||||
c.List.Items = append(c.List.Items, message)
|
||||
}
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
package components
|
||||
|
||||
import "github.com/gizak/termui"
|
||||
|
||||
func CreateInputComponent() *termui.Par {
|
||||
compInput := termui.NewPar("")
|
||||
compInput.Height = 3
|
||||
return compInput
|
||||
}
|
||||
|
||||
func CreateChannelsComponent(inputHeight int) *termui.List {
|
||||
channels := []string{
|
||||
"general",
|
||||
"random",
|
||||
}
|
||||
|
||||
compChannels := termui.NewList()
|
||||
compChannels.Items = channels
|
||||
compChannels.BorderLabel = "Channels"
|
||||
compChannels.Height = termui.TermHeight() - inputHeight
|
||||
compChannels.Overflow = "wrap"
|
||||
|
||||
return compChannels
|
||||
}
|
||||
|
||||
func CreateChatComponent(inputHeight int) *termui.List {
|
||||
messages := []string{
|
||||
"[jp] hello world",
|
||||
"[erroneousboat] foo bar",
|
||||
}
|
||||
|
||||
compChat := termui.NewList()
|
||||
compChat.Items = messages
|
||||
compChat.BorderLabel = "Channel01"
|
||||
compChat.Height = termui.TermHeight() - inputHeight
|
||||
compChat.Overflow = "wrap"
|
||||
|
||||
return compChat
|
||||
}
|
||||
|
||||
func CreateModeComponent() *termui.Par {
|
||||
compMode := termui.NewPar("NORMAL")
|
||||
compMode.Height = 3
|
||||
return compMode
|
||||
}
|
43
src/components/mode.go
Normal file
43
src/components/mode.go
Normal file
@ -0,0 +1,43 @@
|
||||
package components
|
||||
|
||||
import "github.com/gizak/termui"
|
||||
|
||||
type Mode struct {
|
||||
Par *termui.Par
|
||||
}
|
||||
|
||||
func CreateMode() *Mode {
|
||||
mode := &Mode{
|
||||
Par: termui.NewPar("NORMAL"),
|
||||
}
|
||||
|
||||
mode.Par.Height = 3
|
||||
|
||||
return mode
|
||||
}
|
||||
|
||||
// Buffer implements interface termui.Bufferer
|
||||
func (m *Mode) Buffer() termui.Buffer {
|
||||
buf := m.Par.Buffer()
|
||||
return buf
|
||||
}
|
||||
|
||||
// GetHeight implements interface termui.GridBufferer
|
||||
func (m *Mode) GetHeight() int {
|
||||
return m.Par.Block.GetHeight()
|
||||
}
|
||||
|
||||
// SetWidth implements interface termui.GridBufferer
|
||||
func (m *Mode) SetWidth(w int) {
|
||||
m.Par.SetWidth(w)
|
||||
}
|
||||
|
||||
// SetX implements interface termui.GridBufferer
|
||||
func (m *Mode) SetX(x int) {
|
||||
m.Par.SetX(x)
|
||||
}
|
||||
|
||||
// SetY implements interface termui.GridBufferer
|
||||
func (m *Mode) SetY(y int) {
|
||||
m.Par.SetY(y)
|
||||
}
|
25
src/config/config.go
Normal file
25
src/config/config.go
Normal file
@ -0,0 +1,25 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
SlackToken string `json:"slack_token"`
|
||||
}
|
||||
|
||||
func NewConfig(filepath string) (*Config, error) {
|
||||
var cfg Config
|
||||
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(file).Decode(&cfg); err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
@ -1,8 +1,13 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/erroneousboat/slack-term/src/views"
|
||||
"log"
|
||||
|
||||
"github.com/gizak/termui"
|
||||
|
||||
"github.com/erroneousboat/slack-term/src/config"
|
||||
"github.com/erroneousboat/slack-term/src/service"
|
||||
"github.com/erroneousboat/slack-term/src/views"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -11,17 +16,30 @@ const (
|
||||
)
|
||||
|
||||
type AppContext struct {
|
||||
Body *termui.Grid
|
||||
View *views.View
|
||||
Mode string
|
||||
Service *service.SlackService
|
||||
Body *termui.Grid
|
||||
View *views.View
|
||||
Config *config.Config
|
||||
Mode string
|
||||
}
|
||||
|
||||
// TODO: arg Config
|
||||
func CreateAppContext() *AppContext {
|
||||
view := views.CreateChatView()
|
||||
func CreateAppContext(flgConfig string) *AppContext {
|
||||
// Load config
|
||||
config, err := config.NewConfig(flgConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR: not able to load config file: %s", flgConfig)
|
||||
}
|
||||
|
||||
// Create Service
|
||||
svc := service.NewSlackService(config.SlackToken)
|
||||
|
||||
// Create ChatView
|
||||
view := views.CreateChatView(svc)
|
||||
|
||||
return &AppContext{
|
||||
View: view,
|
||||
Mode: CommandMode,
|
||||
Service: svc,
|
||||
View: view,
|
||||
Config: config,
|
||||
Mode: CommandMode,
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gizak/termui"
|
||||
"github.com/nlopes/slack"
|
||||
|
||||
"github.com/erroneousboat/slack-term/src/context"
|
||||
"github.com/erroneousboat/slack-term/src/views"
|
||||
@ -10,6 +13,28 @@ import (
|
||||
func RegisterEventHandlers(ctx *context.AppContext) {
|
||||
termui.Handle("/sys/kbd/", anyKeyHandler(ctx))
|
||||
termui.Handle("/sys/wnd/resize", resizeHandler(ctx))
|
||||
termui.Handle("/timer/1s", timeHandler(ctx))
|
||||
|
||||
// TODO: check channel of message should be added to correct channel
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case msg := <-ctx.Service.RTM.IncomingEvents:
|
||||
switch ev := msg.Data.(type) {
|
||||
case *slack.MessageEvent:
|
||||
var name string
|
||||
user, err := ctx.Service.Client.GetUserInfo(ev.User)
|
||||
if err == nil {
|
||||
name = user.Name
|
||||
} else {
|
||||
name = "unknown"
|
||||
}
|
||||
msg := fmt.Sprintf("[%s] %s", name, ev.Text)
|
||||
ctx.View.Chat.AddMessage(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func anyKeyHandler(ctx *context.AppContext) func(termui.Event) {
|
||||
@ -60,6 +85,11 @@ func resizeHandler(ctx *context.AppContext) func(termui.Event) {
|
||||
}
|
||||
}
|
||||
|
||||
func timeHandler(ctx *context.AppContext) func(termui.Event) {
|
||||
return func(e termui.Event) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: resize only seems to work for width and resizing it too small
|
||||
// will cause termui to panic
|
||||
func actionResize(ctx *context.AppContext) {
|
||||
@ -103,12 +133,23 @@ func actionQuit() {
|
||||
|
||||
func actionInsertMode(ctx *context.AppContext) {
|
||||
ctx.Mode = context.InsertMode
|
||||
ctx.View.Mode.Text = "INSERT"
|
||||
ctx.View.Mode.Par.Text = "INSERT"
|
||||
termui.Render(ctx.View.Mode)
|
||||
}
|
||||
|
||||
func actionCommandMode(ctx *context.AppContext) {
|
||||
ctx.Mode = context.CommandMode
|
||||
ctx.View.Mode.Text = "NORMAL"
|
||||
ctx.View.Mode.Par.Text = "NORMAL"
|
||||
termui.Render(ctx.View.Mode)
|
||||
}
|
||||
|
||||
// TODO: get message for channel
|
||||
func actionGetMessages(ctx *context.AppContext) {
|
||||
ctx.View.Chat.GetMessages(ctx.Service)
|
||||
termui.Render(ctx.View.Chat)
|
||||
}
|
||||
|
||||
func actionGetChannels(ctx *context.AppContext) {
|
||||
ctx.View.Channels.GetChannels(ctx.Service)
|
||||
termui.Render(ctx.View.Channels)
|
||||
}
|
||||
|
29
src/main.go
29
src/main.go
@ -1,6 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os/user"
|
||||
"path"
|
||||
|
||||
"github.com/erroneousboat/slack-term/src/context"
|
||||
"github.com/erroneousboat/slack-term/src/handlers"
|
||||
|
||||
@ -8,16 +13,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Start terminal user interface
|
||||
err := termui.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer termui.Close()
|
||||
|
||||
// create context
|
||||
ctx := context.CreateAppContext()
|
||||
// Get home dir for config file default
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// setup view
|
||||
// Parse flags
|
||||
flgConfig := flag.String(
|
||||
"config",
|
||||
path.Join(usr.HomeDir, "slack-term.json"),
|
||||
"location of config file",
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
// Create context
|
||||
ctx := context.CreateAppContext(*flgConfig)
|
||||
|
||||
// Setup body
|
||||
termui.Body.AddRows(
|
||||
termui.NewRow(
|
||||
termui.NewCol(1, 0, ctx.View.Channels),
|
||||
@ -31,9 +51,10 @@ func main() {
|
||||
termui.Body.Align()
|
||||
termui.Render(termui.Body)
|
||||
|
||||
// Set body in context
|
||||
ctx.Body = termui.Body
|
||||
|
||||
// register handlers
|
||||
// Register handlers
|
||||
handlers.RegisterEventHandlers(ctx)
|
||||
|
||||
termui.Loop()
|
||||
|
88
src/service/slack.go
Normal file
88
src/service/slack.go
Normal file
@ -0,0 +1,88 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/nlopes/slack"
|
||||
)
|
||||
|
||||
type SlackService struct {
|
||||
Client *slack.Client
|
||||
RTM *slack.RTM
|
||||
Channels []slack.Channel
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
func NewSlackService(token string) *SlackService {
|
||||
svc := new(SlackService)
|
||||
|
||||
svc.Client = slack.New(token)
|
||||
svc.RTM = svc.Client.NewRTM()
|
||||
|
||||
go svc.RTM.ManageConnection()
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func (s *SlackService) Connect() {
|
||||
|
||||
}
|
||||
|
||||
func (s *SlackService) GetChannels() []Channel {
|
||||
var chans []Channel
|
||||
|
||||
slackChans, err := s.Client.GetChannels(true)
|
||||
if err != nil {
|
||||
chans = append(chans, Channel{})
|
||||
}
|
||||
|
||||
s.Channels = slackChans
|
||||
|
||||
for _, slackChan := range slackChans {
|
||||
chans = append(chans, Channel{slackChan.ID, slackChan.Name})
|
||||
}
|
||||
|
||||
return chans
|
||||
}
|
||||
|
||||
func (s *SlackService) SendMessage(message string) {}
|
||||
|
||||
func (s *SlackService) GetMessages(channel string) []string {
|
||||
// https://api.slack.com/methods/channels.history
|
||||
historyParams := slack.HistoryParameters{
|
||||
// Latest: "now",
|
||||
// Oldest: 0,
|
||||
Count: 50,
|
||||
Inclusive: false,
|
||||
Unreads: false,
|
||||
}
|
||||
|
||||
// https://godoc.org/github.com/nlopes/slack#History
|
||||
history, err := s.Client.GetChannelHistory(channel, historyParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// TODO: this takes a long time, maybe use some dynamic programming
|
||||
var messages []string
|
||||
for _, message := range history.Messages {
|
||||
var name string
|
||||
user, err := s.Client.GetUserInfo(message.User)
|
||||
if err == nil {
|
||||
name = user.Name
|
||||
} else {
|
||||
name = "unknown"
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("[%s] %s", name, message.Text)
|
||||
messages = append(messages, msg)
|
||||
}
|
||||
|
||||
return messages
|
||||
}
|
@ -2,6 +2,7 @@ package views
|
||||
|
||||
import (
|
||||
"github.com/erroneousboat/slack-term/src/components"
|
||||
"github.com/erroneousboat/slack-term/src/service"
|
||||
|
||||
"github.com/gizak/termui"
|
||||
)
|
||||
@ -9,15 +10,15 @@ import (
|
||||
type View struct {
|
||||
Input *components.Input
|
||||
Chat *components.Chat
|
||||
Channels *termui.List
|
||||
Mode *termui.Par
|
||||
Channels *components.Channels
|
||||
Mode *components.Mode
|
||||
}
|
||||
|
||||
func CreateChatView() *View {
|
||||
func CreateChatView(svc *service.SlackService) *View {
|
||||
input := components.CreateInput()
|
||||
channels := components.CreateChannelsComponent(input.Par.Height)
|
||||
chat := components.CreateChat(input.Par.Height)
|
||||
mode := components.CreateModeComponent()
|
||||
channels := components.CreateChannels(svc, input.Par.Height)
|
||||
chat := components.CreateChat(svc, input.Par.Height)
|
||||
mode := components.CreateMode()
|
||||
|
||||
view := &View{
|
||||
Input: input,
|
||||
|
Loading…
x
Reference in New Issue
Block a user