rooms.go (5219B)
1 package matrix 2 3 import ( 4 "bytes" 5 "image" 6 "image/draw" 7 "image/png" 8 "strings" 9 10 "github.com/Nordgedanken/Morpheus/matrix/db" 11 "github.com/dgraph-io/badger" 12 "github.com/matrix-org/gomatrix" 13 "github.com/rhinoman/go-commonmark" 14 log "github.com/sirupsen/logrus" 15 "github.com/therecipe/qt/gui" 16 ) 17 18 // Room saves the information of a Room 19 type Room struct { 20 cli *gomatrix.Client 21 RoomID string 22 RoomName string 23 RoomAvatarURL string 24 RoomTopic string 25 } 26 27 // NewRoom Inits a new Room struct 28 func NewRoom(roomID string, cli *gomatrix.Client) (room *Room) { 29 room = &Room{RoomID: roomID, cli: cli} 30 return 31 } 32 33 func (r *Room) crawlRoomAvatarURL() { 34 roomAvatar := struct { 35 URL string `json:"url"` 36 }{} 37 r.cli.StateEvent(r.RoomID, "m.room.avatar", "", &roomAvatar) 38 r.RoomAvatarURL = roomAvatar.URL 39 } 40 41 func (r *Room) crawlRoomTopic() { 42 roomTopic := struct { 43 Topic string `json:"topic"` 44 }{} 45 r.cli.StateEvent(r.RoomID, "m.room.topic", "", &roomTopic) 46 r.RoomTopic = roomTopic.Topic 47 } 48 49 // GetRoomTopic returns the Topic of the Room and crawls it if needed 50 func (r *Room) GetRoomTopic() (topic string) { 51 if r.RoomTopic == "" { 52 r.crawlRoomTopic() 53 } 54 55 mardownMessage := commonmark.Md2Html(r.RoomTopic, 0) 56 57 if mardownMessage == r.RoomTopic { 58 topic = r.RoomTopic 59 return 60 } else { 61 r.RoomTopic = mardownMessage 62 topic = r.RoomTopic 63 return 64 } 65 } 66 67 // GetRoomAvatar generates the Avatar Image for a Room 68 func (r *Room) GetRoomAvatar() (avatarResp *gui.QPixmap, err error) { 69 // Get the Avatar URL if needed 70 if r.RoomAvatarURL == "" { 71 r.crawlRoomAvatarURL() 72 } 73 74 // Get the image Data 75 cacheDB, DBOpenErr := db.OpenCacheDB() 76 if DBOpenErr != nil { 77 log.Fatalln(DBOpenErr) 78 } 79 80 // Init local vars 81 var roomAvatarData []byte 82 var IMGdata []byte 83 84 // Get cache 85 DBErr := cacheDB.View(func(txn *badger.Txn) error { 86 roomAvatarDataItem, QueryErr := txn.Get([]byte("room|" + r.RoomID + "|84x84")) 87 if QueryErr != nil && QueryErr != badger.ErrKeyNotFound { 88 return QueryErr 89 } 90 if QueryErr != badger.ErrKeyNotFound { 91 roomAvatarDataBytes, roomAvatarDataErr := roomAvatarDataItem.Value() 92 roomAvatarData = roomAvatarDataBytes 93 return roomAvatarDataErr 94 } 95 return nil 96 }) 97 if DBErr != nil { 98 err = DBErr 99 return 100 } 101 102 //If cache is empty do a ServerQuery 103 if len(roomAvatarData) <= 0 { 104 // If avatarURL is not empty (aka. has a avatar set) download it at the size of 100x100. Else make the data string empty 105 if r.RoomAvatarURL != "" { 106 hsURL := r.cli.HomeserverURL.String() 107 roomAvatarURLSplits := strings.Split(strings.Replace(r.RoomAvatarURL, "mxc://", "", -1), "/") 108 109 urlPath := hsURL + "/_matrix/media/r0/thumbnail/" + roomAvatarURLSplits[0] + "/" + roomAvatarURLSplits[1] + "?width=84&height=84&method=crop" 110 111 data, ReqErr := r.cli.MakeRequest("GET", urlPath, nil, nil) 112 if ReqErr != nil { 113 err = ReqErr 114 return 115 } 116 IMGdata = data 117 } else { 118 log.Println("Generating Room Avatar") 119 var GenerateImgErr error 120 var roomName string 121 if r.RoomName == "" { 122 r.crawlRoomName() 123 } 124 roomName = r.RoomName 125 log.Println(roomName) 126 if roomName == "" { 127 roomName = "#" 128 } 129 IMGdata, GenerateImgErr = generateGenericImages(roomName, 84) 130 if GenerateImgErr != nil { 131 err = GenerateImgErr 132 return 133 } 134 } 135 136 // Update cache 137 DBSetErr := cacheDB.Update(func(txn *badger.Txn) error { 138 DBSetErr := txn.Set([]byte("room|"+r.RoomID+"|84x84"), IMGdata) 139 return DBSetErr 140 }) 141 if DBSetErr != nil { 142 err = DBSetErr 143 return 144 } 145 146 } else { 147 IMGdata = roomAvatarData 148 } 149 150 reader := bytes.NewReader(IMGdata) 151 srcIMG, _, DecodeErr := image.Decode(reader) 152 if DecodeErr != nil { 153 err = DecodeErr 154 } 155 156 // Convert avatarimage to QPixmap for usage in QT 157 canvas := image.NewRGBA(srcIMG.Bounds()) 158 cx := srcIMG.Bounds().Min.X + srcIMG.Bounds().Dx()/2 159 cy := srcIMG.Bounds().Min.Y + srcIMG.Bounds().Dy()/2 160 draw.DrawMask(canvas, canvas.Bounds(), srcIMG, image.ZP, &circle{image.Point{cx, cy}, cx}, image.ZP, draw.Over) 161 162 avatar := gui.NewQPixmap() 163 buf := new(bytes.Buffer) 164 ConvErr := png.Encode(buf, canvas) 165 if ConvErr != nil { 166 err = ConvErr 167 } 168 169 str := buf.String() 170 avatar.LoadFromData(str, uint(len(str)), "", 0) 171 avatarResp = avatar 172 return 173 } 174 175 func (r *Room) crawlRoomName() { 176 roomName := struct { 177 Name string `json:"name"` 178 }{} 179 roomCanoncialAlias := struct { 180 Alias string `json:"alias"` 181 }{} 182 183 if roomNameStateEventErr := r.cli.StateEvent(r.RoomID, "m.room.name", "", &roomName); roomNameStateEventErr != nil { 184 log.Println(roomNameStateEventErr) 185 // Not returning as a Error NotFound is allowed 186 } 187 if roomName.Name == "" { 188 if roomCanoncialAliasStateEventErr := r.cli.StateEvent(r.RoomID, "m.room.canonical_alias", "", &roomCanoncialAlias); roomCanoncialAliasStateEventErr != nil { 189 log.Println(roomCanoncialAliasStateEventErr) 190 // Not returning as a Error NotFound is allowed 191 } 192 if roomCanoncialAlias.Alias == "" { 193 r.RoomName = r.RoomID 194 } else { 195 r.RoomName = roomCanoncialAlias.Alias 196 } 197 } else { 198 r.RoomName = roomName.Name 199 } 200 201 } 202 203 // GetRoomName gives you the name of the current Room 204 func (r *Room) GetRoomName() (name string) { 205 if r.RoomName == "" { 206 r.crawlRoomName() 207 } 208 name = r.RoomName 209 return 210 }