WebRTC audio/video call and conferencing server.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

173 lines
3.9 KiB

/*
* Spreed WebRTC.
* Copyright (C) 2013-2015 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package channelling
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/binary"
"log"
"strings"
"sync"
"time"
)
var imageFilenames map[string]string
type Image struct {
updateIdx int
lastChange time.Time
lastChangeId string
sessionid string
mimetype string
data []byte
}
func (img *Image) LastChangeID() string {
return img.lastChangeId
}
func (img *Image) LastChange() time.Time {
return img.lastChange
}
func (img *Image) MimeType() string {
return img.mimetype
}
func (img *Image) Reader() *bytes.Reader {
return bytes.NewReader(img.data)
}
type ImageCache interface {
Update(sessionId string, image string) string
Get(imageId string) *Image
Delete(sessionId string)
}
type imageCache struct {
images map[string]*Image
sessionImages map[string]string
mutex sync.RWMutex
}
func NewImageCache() ImageCache {
result := &imageCache{}
result.images = make(map[string]*Image)
result.sessionImages = make(map[string]string)
if imageFilenames == nil {
imageFilenames = map[string]string{
"image/png": "picture.png",
"image/jpeg": "picture.jpg",
"image/gif": "picture.gif",
"image/webp": "picture.webp",
}
}
return result
}
func (self *imageCache) Update(sessionId string, image string) string {
mimetype := "image/x-unknown"
pos := strings.Index(image, ";")
if pos != -1 {
mimetype = image[:pos]
image = image[pos+1:]
}
pos = strings.Index(image, ",")
var decoded []byte
var err error
if pos != -1 {
encoding := image[:pos]
switch encoding {
case "base64":
decoded, err = base64.StdEncoding.DecodeString(image[pos+1:])
if err != nil {
return ""
}
default:
log.Println("Unknown encoding", encoding)
return ""
}
} else {
decoded = []byte(image[pos+1:])
}
var img *Image
self.mutex.RLock()
result, ok := self.sessionImages[sessionId]
if !ok {
self.mutex.RUnlock()
imageId := make([]byte, 15, 15)
if _, err = rand.Read(imageId); err != nil {
return ""
}
result = base64.URLEncoding.EncodeToString(imageId)
img = &Image{sessionid: sessionId}
self.mutex.Lock()
resultTmp, ok := self.sessionImages[sessionId]
if !ok {
self.sessionImages[sessionId] = result
self.images[result] = img
} else {
result = resultTmp
img = self.images[result]
}
self.mutex.Unlock()
} else {
img = self.images[result]
self.mutex.RUnlock()
}
if mimetype != img.mimetype || !bytes.Equal(img.data, decoded) {
img.updateIdx++
img.lastChange = time.Now()
tmp := make([]byte, binary.MaxVarintLen64)
count := binary.PutUvarint(tmp, uint64(img.lastChange.UnixNano()))
img.lastChangeId = base64.URLEncoding.EncodeToString(tmp[:count])
img.mimetype = mimetype
img.data = decoded
}
result += "/" + img.lastChangeId
filename, ok := imageFilenames[mimetype]
if ok {
result += "/" + filename
}
return result
}
func (self *imageCache) Get(imageId string) *Image {
self.mutex.RLock()
image := self.images[imageId]
self.mutex.RUnlock()
return image
}
func (self *imageCache) Delete(sessionId string) {
self.mutex.Lock()
imageId, ok := self.sessionImages[sessionId]
if ok {
delete(self.sessionImages, sessionId)
delete(self.images, imageId)
}
self.mutex.Unlock()
}