forked from External/ergo
adjust commands to utilize channel names add new config variables fix mention race condition
191 lines
4.8 KiB
Go
191 lines
4.8 KiB
Go
package irc
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/cshum/imagor/imagorpath"
|
|
"github.com/ergochat/ergo/irc/caps"
|
|
"github.com/ergochat/irc-go/ircmsg"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var ctx = context.Background()
|
|
|
|
func (channel *Channel) RedisBroadcast(message ...string) {
|
|
if channel.server.redis == nil {
|
|
return
|
|
}
|
|
err := channel.server.redis.Publish(ctx, "channel."+channel.NameCasefolded(), strings.Join(message, " ")).Err()
|
|
if err != nil {
|
|
fmt.Printf("Channel broadcast error: %v", err)
|
|
}
|
|
}
|
|
|
|
func (client *Client) RedisBroadcast(message ...string) {
|
|
err := client.server.redis.Publish(ctx, "user."+client.NickCasefolded(), strings.Join(message, " ")).Err()
|
|
if err != nil {
|
|
fmt.Printf("User broadcast error: %v", err)
|
|
}
|
|
}
|
|
|
|
func (channel *Channel) Broadcast(command string, params ...string) {
|
|
for _, member := range channel.Members() {
|
|
for _, session := range member.Sessions() {
|
|
session.Send(nil, member.server.name, command, params...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ChannelSub Actions and info centering around channels
|
|
func (server *Server) ChannelSub() {
|
|
pubsub := server.redis.PSubscribe(ctx, "channel.*")
|
|
defer pubsub.Close()
|
|
|
|
ch := pubsub.Channel()
|
|
|
|
for msg := range ch {
|
|
server.logger.Info("RedisMessage", msg.Channel, msg.Payload)
|
|
line := strings.Split(msg.Payload, " ")
|
|
channelName := strings.SplitN(msg.Channel, ".", 2)[1]
|
|
channel := server.channels.Get(channelName)
|
|
if len(line) == 0 {
|
|
println("Empty string dumped into ", msg.Channel, " channel")
|
|
}
|
|
if channel == nil {
|
|
server.logger.Warning("RedisMessage", "Unknown channel")
|
|
continue
|
|
}
|
|
|
|
switch line[0] {
|
|
case "VOICEPART":
|
|
channel.Broadcast("VOICEPART", channelName, line[1])
|
|
case "VOICESTATE":
|
|
channel.Broadcast("VOICESTATE", channelName, line[1])
|
|
case "BROADCASTTO":
|
|
for _, person := range channel.Members() {
|
|
person.Send(nil, server.name, line[1], line[2:]...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// UserSub Handles things pertaining to users
|
|
func (server *Server) UserSub() {
|
|
pubsub := server.redis.PSubscribe(ctx, "user.*")
|
|
defer pubsub.Close()
|
|
|
|
ch := pubsub.Channel()
|
|
|
|
for msg := range ch {
|
|
server.logger.Info("RedisMessage", msg.Channel, msg.Payload)
|
|
line := strings.Split(msg.Payload, " ")
|
|
userName := strings.SplitN(msg.Channel, ".", 2)[1]
|
|
user := server.clients.Get(userName)
|
|
if len(line) == 0 {
|
|
println("Empty string dumped into ", msg.Channel, " channel")
|
|
}
|
|
|
|
switch line[0] {
|
|
case "FULLYREMOVE":
|
|
if user != nil {
|
|
user.destroy(nil)
|
|
err := server.accounts.Unregister(user.Account(), true)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
break
|
|
case "BROADCASTAS":
|
|
if user != nil {
|
|
// I'm not too sure what the capability bit is, I think it's just ones that match
|
|
for friend := range user.Friends(caps.ExtendedNames) {
|
|
friend.Send(nil, user.NickMaskString(), line[1], line[2:]...)
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func startRedis(server *Server) {
|
|
go server.ChannelSub()
|
|
go server.UserSub()
|
|
}
|
|
|
|
func (server *Server) GenerateImagorSignaturesFromMessage(message *ircmsg.Message) string {
|
|
line, err := message.Line()
|
|
if err == nil {
|
|
return server.GenerateImagorSignatures(line)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (server *Server) GetUrlMime(url string) string {
|
|
config := server.Config()
|
|
// hacky, should fix
|
|
if !strings.Contains(url, "?") {
|
|
url += "?"
|
|
}
|
|
params := imagorpath.Params{
|
|
Image: url,
|
|
Meta: true,
|
|
}
|
|
metaPath := imagorpath.Generate(params, imagorpath.NewHMACSigner(sha256.New, 0, config.Cef.Imagor.Secret))
|
|
client := http.Client{
|
|
Timeout: 5 * time.Second,
|
|
}
|
|
resp, err := client.Get(config.Cef.Imagor.Url + metaPath)
|
|
if err != nil {
|
|
println("Failed on the initial get")
|
|
println(err.Error())
|
|
return ""
|
|
}
|
|
defer resp.Body.Close()
|
|
var meta map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&meta)
|
|
if err != nil {
|
|
println("Failed on the JSON decode")
|
|
return ""
|
|
}
|
|
contentType, valid := meta["format"].(string)
|
|
fmt.Printf("%+v\n", meta)
|
|
if !valid {
|
|
println("No content type")
|
|
return ""
|
|
}
|
|
return contentType
|
|
}
|
|
|
|
var urlRegex = regexp.MustCompile("https?:\\/\\/[\\w-]+(\\.[\\w-]+)+([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?")
|
|
|
|
// Process a message to add Imagor signatures
|
|
func (server *Server) GenerateImagorSignatures(str string) string {
|
|
urls := urlRegex.FindAllString(str, -1)
|
|
var sigs []string
|
|
for _, url := range urls {
|
|
params := imagorpath.Params{
|
|
Image: url,
|
|
FitIn: true,
|
|
Width: 600,
|
|
Height: 600,
|
|
}
|
|
path := imagorpath.Generate(params, imagorpath.NewHMACSigner(sha256.New, 0, server.Config().Cef.Imagor.Secret))
|
|
signature := path[:strings.IndexByte(path, '/')]
|
|
contentType := server.GetUrlMime(url)
|
|
if contentType != "" {
|
|
sigs = append(sigs, signature+"|"+strings.ReplaceAll(contentType, "/", "_"))
|
|
} else {
|
|
sigs = append(sigs, signature)
|
|
}
|
|
|
|
}
|
|
if len(sigs) > 0 {
|
|
return strings.Join(sigs, ",")
|
|
}
|
|
return ""
|
|
}
|