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) { channel.BroadcastFrom(channel.server.name, command, params...) } func (channel *Channel) BroadcastFrom(prefix string, command string, params ...string) { for _, member := range channel.Members() { for _, session := range member.Sessions() { session.Send(nil, prefix, 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], line[2], line[3]) 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) 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 "" }