diff --git a/bridge/config/config.go b/bridge/config/config.go index 1627adc2..351e6cad 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -2,14 +2,15 @@ package config import ( "bytes" - "github.com/fsnotify/fsnotify" - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" - prefixed "github.com/x-cray/logrus-prefixed-formatter" "os" "strings" "sync" "time" + + "github.com/fsnotify/fsnotify" + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" + prefixed "github.com/x-cray/logrus-prefixed-formatter" ) const ( @@ -76,6 +77,7 @@ type Protocol struct { MediaDownloadSize int // all protocols MediaServerDownload string MediaServerUpload string + MediaDownloadPath string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server. MessageDelay int // IRC, time in millisecond to wait between messages MessageFormat string // telegram MessageLength int // IRC, max length of a message allowed diff --git a/gateway/gateway.go b/gateway/gateway.go index eb5bbe92..b926912a 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -3,6 +3,10 @@ package gateway import ( "bytes" "fmt" + "io/ioutil" + "net/http" + "os" + "github.com/42wim/matterbridge/bridge" "github.com/42wim/matterbridge/bridge/api" "github.com/42wim/matterbridge/bridge/config" @@ -18,16 +22,16 @@ import ( "github.com/42wim/matterbridge/bridge/telegram" "github.com/42wim/matterbridge/bridge/xmpp" "github.com/42wim/matterbridge/bridge/zulip" + "github.com/hashicorp/golang-lru" log "github.com/sirupsen/logrus" // "github.com/davecgh/go-spew/spew" "crypto/sha1" - "github.com/hashicorp/golang-lru" - "github.com/peterhellberg/emojilib" - "net/http" "path/filepath" "regexp" "strings" "time" + + "github.com/peterhellberg/emojilib" ) type Gateway struct { @@ -411,46 +415,83 @@ func (gw *Gateway) modifyMessage(msg *config.Message) { } } +// handleFiles uploads or places all files on the given msg to the MediaServer and +// adds the new URL of the file on the MediaServer onto the given msg. func (gw *Gateway) handleFiles(msg *config.Message) { reg := regexp.MustCompile("[^a-zA-Z0-9]+") - // if we don't have a attachfield or we don't have a mediaserver configured return - if msg.Extra == nil || gw.Config.General.MediaServerUpload == "" { + + // If we don't have a attachfield or we don't have a mediaserver configured return + if msg.Extra == nil || (gw.Config.General.MediaServerUpload == "" && gw.Config.General.MediaDownloadPath == "") { return } - // if we actually have files, start uploading them to the mediaserver - if len(msg.Extra["file"]) > 0 { - client := &http.Client{ - Timeout: time.Second * 5, - } - for i, f := range msg.Extra["file"] { - fi := f.(config.FileInfo) - ext := filepath.Ext(fi.Name) - fi.Name = fi.Name[0 : len(fi.Name)-len(ext)] - fi.Name = reg.ReplaceAllString(fi.Name, "_") - fi.Name = fi.Name + ext - sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data)) - reader := bytes.NewReader(*fi.Data) + // If we don't have files, nothing to upload. + if len(msg.Extra["file"]) == 0 { + return + } + + client := &http.Client{ + Timeout: time.Second * 5, + } + + for i, f := range msg.Extra["file"] { + fi := f.(config.FileInfo) + ext := filepath.Ext(fi.Name) + fi.Name = fi.Name[0 : len(fi.Name)-len(ext)] + fi.Name = reg.ReplaceAllString(fi.Name, "_") + fi.Name = fi.Name + ext + + sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data))[:8] + + if gw.Config.General.MediaServerUpload != "" { + // Use MediaServerUpload. Upload using a PUT HTTP request and basicauth. + url := gw.Config.General.MediaServerUpload + "/" + sha1sum + "/" + fi.Name - durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name - extra := msg.Extra["file"][i].(config.FileInfo) - extra.URL = durl - req, err := http.NewRequest("PUT", url, reader) + + req, err := http.NewRequest("PUT", url, bytes.NewReader(*fi.Data)) if err != nil { - flog.Errorf("mediaserver upload failed: %#v", err) + flog.Errorf("mediaserver upload failed, could not create request: %#v", err) continue } + + flog.Debugf("mediaserver upload url: %s", url) + req.Header.Set("Content-Type", "binary/octet-stream") _, err = client.Do(req) if err != nil { - flog.Errorf("mediaserver upload failed: %#v", err) + flog.Errorf("mediaserver upload failed, could not Do request: %#v", err) + continue + } + } else { + // Use MediaServerPath. Place the file on the current filesystem. + + dir := gw.Config.General.MediaDownloadPath + "/" + sha1sum + err := os.Mkdir(dir, os.ModePerm) + if err != nil && !os.IsExist(err) { + flog.Errorf("mediaserver path failed, could not mkdir: %s %#v", err, err) + continue + } + + path := dir + "/" + fi.Name + flog.Debugf("mediaserver path placing file: %s", path) + + err = ioutil.WriteFile(path, *fi.Data, os.ModePerm) + if err != nil { + flog.Errorf("mediaserver path failed, could not writefile: %s %#v", err, err) continue } - flog.Debugf("mediaserver download URL = %s", durl) - // we uploaded the file successfully. Add the SHA - extra.SHA = sha1sum - msg.Extra["file"][i] = extra } + + // Download URL. + durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name + + flog.Debugf("mediaserver download URL = %s", durl) + + // We uploaded/placed the file successfully. Add the SHA and URL. + extra := msg.Extra["file"][i].(config.FileInfo) + extra.URL = durl + extra.SHA = sha1sum + msg.Extra["file"][i] = extra } } diff --git a/matterbridge.go b/matterbridge.go index f05a745b..df138028 100644 --- a/matterbridge.go +++ b/matterbridge.go @@ -3,13 +3,14 @@ package main import ( "flag" "fmt" + "os" + "strings" + "github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/gateway" "github.com/google/gops/agent" log "github.com/sirupsen/logrus" prefixed "github.com/x-cray/logrus-prefixed-formatter" - "os" - "strings" ) var ( diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample index 6f81baf6..1bc4f3b4 100644 --- a/matterbridge.toml.sample +++ b/matterbridge.toml.sample @@ -1306,10 +1306,13 @@ RemoteNickFormat="[{PROTOCOL}] <{NICK}> " StripNick=false -#MediaServerUpload and MediaServerDownload are used for uploading images/files/video to -#a remote "mediaserver" (a webserver like caddy for example). -#When configured images/files uploaded on bridges like mattermost,slack, telegram will be downloaded -#and uploaded again to MediaServerUpload URL +#MediaServerUpload (or MediaDownloadPath) and MediaServerDownload are used for uploading +#images/files/video to a remote "mediaserver" (a webserver like caddy for example). +#When configured images/files uploaded on bridges like mattermost, slack, telegram will be +#downloaded and uploaded again to MediaServerUpload URL +#MediaDownloadPath is the filesystem path where the media file will be placed, instead of uploaded, +#for if Matterbridge has write access to the directory your webserver is serving. +#It is an alternative to MediaServerUpload. #The MediaServerDownload will be used so that bridges without native uploading support: #gitter, irc and xmpp will be shown links to the files on MediaServerDownload # @@ -1317,6 +1320,8 @@ StripNick=false #OPTIONAL (default empty) MediaServerUpload="https://user:pass@yourserver.com/upload" #OPTIONAL (default empty) +MediaDownloadPath="/srv/http/yourserver.com/public/download" +#OPTIONAL (default empty) MediaServerDownload="https://youserver.com/download" #MediaDownloadSize is the maximum size of attachments, videos, images