morpheus

A Matrix client written in Go-QT
git clone git://archive.git.mtrnord.blog/Nordgedanken/morpheus.git
Log | Files | Refs | README | LICENSE

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 }