PLT-902 switching to push proxy server

This commit is contained in:
=Corey Hulen
2015-11-30 22:38:38 -08:00
parent b717a8100c
commit 68765a8f21
9 changed files with 178 additions and 56 deletions

View File

@@ -536,7 +536,7 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team,
l4g.Error("Failed to send mention email successfully email=%v err=%v", profileMap[id].Email, err)
}
if len(utils.Cfg.EmailSettings.ApplePushServer) > 0 {
if *utils.Cfg.EmailSettings.SendPushNotifications {
sessionChan := Srv.Store.Session().GetSessions(id)
if result := <-sessionChan; result.Err != nil {
l4g.Error("Failed to retrieve sessions in notifications id=%v, err=%v", id, result.Err)
@@ -548,7 +548,19 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team,
if len(session.DeviceId) > 0 && alreadySeen[session.DeviceId] == "" && strings.HasPrefix(session.DeviceId, "apple:") {
alreadySeen[session.DeviceId] = session.DeviceId
utils.SendAppleNotifyAndForget(strings.TrimPrefix(session.DeviceId, "apple:"), subjectPage.Render(), 1)
msg := model.PushNotification{}
msg.Platform = model.PUSH_NOTIFY_APPLE
msg.Message = subjectPage.Render()
msg.Badge = 1
msg.DeviceId = strings.TrimPrefix(session.DeviceId, "apple:")
msg.ServerId = utils.CfgDiagnosticId
httpClient := http.Client{}
request, _ := http.NewRequest("POST", *utils.Cfg.EmailSettings.PushNotificationServer+"/api/v1/send_push", strings.NewReader(msg.ToJson()))
if _, err := httpClient.Do(request); err != nil {
l4g.Error("Failed to send push notificationid=%v, err=%v", id, err)
}
}
}
}

View File

@@ -68,9 +68,8 @@
"ConnectionSecurity": "",
"InviteSalt": "bjlSR4QqkXFBr7TP4oDzlfZmcNuH9YoS",
"PasswordResetSalt": "vZ4DcKyVVRlKHHJpexcuXzojkE5PZ5eL",
"ApplePushServer": "",
"ApplePushCertPublic": "",
"ApplePushCertPrivate": ""
"SendPushNotifications": true,
"PushNotificationServer": "https://push.mattermost.com"
},
"RateLimitSettings": {
"EnableRateLimiter": true,

View File

@@ -68,6 +68,7 @@ func main() {
manualtesting.InitManualTesting()
}
setDiagnosticId()
runSecurityAndDiagnosticsJobAndForget()
// wait for kill signal before attempting to gracefully shutdown
@@ -80,6 +81,21 @@ func main() {
}
}
func setDiagnosticId() {
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
props := result.Data.(model.StringMap)
id := props[model.SYSTEM_DIAGNOSTIC_ID]
if len(id) == 0 {
id = model.NewId()
systemId := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
<-api.Srv.Store.System().Save(systemId)
}
utils.CfgDiagnosticId = id
}
}
func runSecurityAndDiagnosticsJobAndForget() {
go func() {
for {
@@ -92,15 +108,9 @@ func runSecurityAndDiagnosticsJobAndForget() {
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
l4g.Debug("Checking for security update from Mattermost")
id := props[model.SYSTEM_DIAGNOSTIC_ID]
if len(id) == 0 {
id = model.NewId()
systemId := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
<-api.Srv.Store.System().Save(systemId)
}
v := url.Values{}
v.Set(utils.PROP_DIAGNOSTIC_ID, id)
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)

View File

@@ -96,11 +96,8 @@ type EmailSettings struct {
ConnectionSecurity string
InviteSalt string
PasswordResetSalt string
// For Future Use
ApplePushServer string
ApplePushCertPublic string
ApplePushCertPrivate string
SendPushNotifications *bool
PushNotificationServer *string
}
type RateLimitSettings struct {
@@ -181,6 +178,17 @@ func (o *Config) SetDefaults() {
o.TeamSettings.EnableTeamListing = new(bool)
*o.TeamSettings.EnableTeamListing = false
}
if o.EmailSettings.SendPushNotifications == nil {
o.EmailSettings.SendPushNotifications = new(bool)
*o.EmailSettings.SendPushNotifications = true
}
if o.EmailSettings.PushNotificationServer == nil {
o.EmailSettings.PushNotificationServer = new(string)
*o.EmailSettings.PushNotificationServer = "https://push.mattermost.com"
}
}
func (o *Config) IsValid() *AppError {

View File

@@ -0,0 +1,45 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
const (
PUSH_NOTIFY_APPLE = "apple"
PUSH_NOTIFY_ANDROID = "android"
)
type PushNotification struct {
Platform string `json:"platform"`
ServerId string `json:"server_id"`
DeviceId string `json:"device_id"`
Category string `json:"category"`
Sound string `json:"sound"`
Message string `json:"message"`
Badge int `json:"badge"`
ContentAvailable int `json:"cont_ava"`
}
func (me *PushNotification) ToJson() string {
b, err := json.Marshal(me)
if err != nil {
return ""
} else {
return string(b)
}
}
func PushNotificationFromJson(data io.Reader) *PushNotification {
decoder := json.NewDecoder(data)
var me PushNotification
err := decoder.Decode(&me)
if err == nil {
return &me
} else {
return nil
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
"testing"
)
func TestPushNotification(t *testing.T) {
msg := PushNotification{Platform: "test"}
json := msg.ToJson()
result := PushNotificationFromJson(strings.NewReader(json))
if msg.Platform != result.Platform {
t.Fatal("Ids do not match")
}
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package utils
import (
l4g "code.google.com/p/log4go"
"fmt"
"github.com/anachronistic/apns"
"github.com/mattermost/platform/model"
)
func SendAppleNotifyAndForget(deviceId string, message string, badge int) {
go func() {
if err := SendAppleNotify(deviceId, message, badge); err != nil {
l4g.Error(fmt.Sprintf("%v %v", err.Message, err.DetailedError))
}
}()
}
func SendAppleNotify(deviceId string, message string, badge int) *model.AppError {
payload := apns.NewPayload()
payload.Alert = message
payload.Badge = 1
pn := apns.NewPushNotification()
pn.DeviceToken = deviceId
pn.AddPayload(payload)
client := apns.BareClient(Cfg.EmailSettings.ApplePushServer, Cfg.EmailSettings.ApplePushCertPublic, Cfg.EmailSettings.ApplePushCertPrivate)
resp := client.Send(pn)
if resp.Error != nil {
return model.NewAppError("", "Could not send apple push notification", fmt.Sprintf("id=%v err=%v", deviceId, resp.Error))
} else {
return nil
}
}

View File

@@ -24,6 +24,7 @@ const (
)
var Cfg *model.Config = &model.Config{}
var CfgDiagnosticId = ""
var CfgLastModified int64 = 0
var CfgFileName string = ""
var ClientCfg map[string]string = map[string]string{}

View File

@@ -18,6 +18,7 @@ export default class EmailSettings extends React.Component {
this.state = {
sendEmailNotifications: this.props.config.EmailSettings.SendEmailNotifications,
sendPushNotifications: this.props.config.EmailSettings.SendPushNotifications,
saveNeeded: false,
serverError: null,
emailSuccess: null,
@@ -36,6 +37,14 @@ export default class EmailSettings extends React.Component {
s.sendEmailNotifications = false;
}
if (action === 'sendPushNotifications_true') {
s.sendPushNotifications = true;
}
if (action === 'sendPushNotifications_false') {
s.sendPushNotifications = false;
}
this.setState(s);
}
@@ -43,11 +52,12 @@ export default class EmailSettings extends React.Component {
var config = this.props.config;
config.EmailSettings.EnableSignUpWithEmail = ReactDOM.findDOMNode(this.refs.allowSignUpWithEmail).checked;
config.EmailSettings.SendEmailNotifications = ReactDOM.findDOMNode(this.refs.sendEmailNotifications).checked;
config.EmailSettings.SendPushlNotifications = ReactDOM.findDOMNode(this.refs.sendPushNotifications).checked;
config.EmailSettings.RequireEmailVerification = ReactDOM.findDOMNode(this.refs.requireEmailVerification).checked;
config.EmailSettings.SendEmailNotifications = ReactDOM.findDOMNode(this.refs.sendEmailNotifications).checked;
config.EmailSettings.FeedbackName = ReactDOM.findDOMNode(this.refs.feedbackName).value.trim();
config.EmailSettings.FeedbackEmail = ReactDOM.findDOMNode(this.refs.feedbackEmail).value.trim();
config.EmailSettings.SMTPServer = ReactDOM.findDOMNode(this.refs.SMTPServer).value.trim();
config.EmailSettings.PushNotificationServer = ReactDOM.findDOMNode(this.refs.PushNotificationServer).value.trim();
config.EmailSettings.SMTPPort = ReactDOM.findDOMNode(this.refs.SMTPPort).value.trim();
config.EmailSettings.SMTPUsername = ReactDOM.findDOMNode(this.refs.SMTPUsername).value.trim();
config.EmailSettings.SMTPPassword = ReactDOM.findDOMNode(this.refs.SMTPPassword).value.trim();
@@ -525,6 +535,61 @@ export default class EmailSettings extends React.Component {
</div>
</div>
<div className='form-group'>
<label
className='control-label col-sm-4'
htmlFor='sendPushNotifications'
>
{'Send Push Notifications: '}
</label>
<div className='col-sm-8'>
<label className='radio-inline'>
<input
type='radio'
name='sendPushNotifications'
value='true'
ref='sendPushNotifications'
defaultChecked={this.props.config.EmailSettings.SendPushNotifications}
onChange={this.handleChange.bind(this, 'sendPushNotifications_true')}
/>
{'true'}
</label>
<label className='radio-inline'>
<input
type='radio'
name='sendPushNotifications'
value='false'
defaultChecked={!this.props.config.EmailSettings.SendPushNotifications}
onChange={this.handleChange.bind(this, 'sendPushNotifications_false')}
/>
{'false'}
</label>
<p className='help-text'>{'Typically set to true in production. When true, Mattermost attempts to send iOS and Android push notifications through the push notification server.'}</p>
</div>
</div>
<div className='form-group'>
<label
className='control-label col-sm-4'
htmlFor='PushNotificationServer'
>
{'Push Notification Server:'}
</label>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
id='PushNotificationServer'
ref='PushNotificationServer'
placeholder='E.g.: "https://push.mattermost.com"'
defaultValue={this.props.config.EmailSettings.PushNotificationServer}
onChange={this.handleChange}
disabled={!this.state.sendPushNotifications}
/>
<p className='help-text'>{'Location of the push notification server.'}</p>
</div>
</div>
<div className='form-group'>
<div className='col-sm-12'>
{serverError}