2014-05-06 04:52:25 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
2015-02-11 05:06:59 +03:00
"crypto/tls"
2014-05-06 04:52:25 +04:00
"encoding/json"
2015-08-27 18:06:14 +03:00
"fmt"
2014-08-24 16:59:47 +04:00
"io/ioutil"
2015-08-27 18:06:14 +03:00
"strings"
2015-07-25 16:32:04 +03:00
"sync"
2014-06-08 12:45:34 +04:00
"time"
2014-05-06 04:52:25 +04:00
2015-10-24 10:36:47 +03:00
"github.com/Unknwon/com"
2015-08-27 18:06:14 +03:00
"github.com/go-xorm/xorm"
2016-02-21 02:13:12 +03:00
gouuid "github.com/satori/go.uuid"
2015-08-27 18:06:14 +03:00
2015-08-28 18:36:13 +03:00
api "github.com/gogits/go-gogs-client"
2014-06-08 12:45:34 +04:00
"github.com/gogits/gogs/modules/httplib"
2014-05-06 04:52:25 +04:00
"github.com/gogits/gogs/modules/log"
2014-06-08 12:45:34 +04:00
"github.com/gogits/gogs/modules/setting"
2014-05-06 04:52:25 +04:00
)
2014-06-08 12:45:34 +04:00
type HookContentType int
2014-05-06 04:52:25 +04:00
const (
2014-06-08 12:45:34 +04:00
JSON HookContentType = iota + 1
FORM
2014-05-06 04:52:25 +04:00
)
2014-11-13 20:57:00 +03:00
var hookContentTypes = map [ string ] HookContentType {
"json" : JSON ,
"form" : FORM ,
}
// ToHookContentType returns HookContentType by given name.
func ToHookContentType ( name string ) HookContentType {
return hookContentTypes [ name ]
}
2014-11-13 10:32:18 +03:00
func ( t HookContentType ) Name ( ) string {
switch t {
case JSON :
return "json"
case FORM :
return "form"
}
return ""
}
2014-11-13 20:57:00 +03:00
// IsValidHookContentType returns true if given name is a valid hook content type.
func IsValidHookContentType ( name string ) bool {
_ , ok := hookContentTypes [ name ]
return ok
}
2015-08-28 18:36:13 +03:00
type HookEvents struct {
Create bool ` json:"create" `
Push bool ` json:"push" `
}
2014-06-08 12:45:34 +04:00
// HookEvent represents events that will delivery hook.
2014-05-06 04:52:25 +04:00
type HookEvent struct {
2015-08-28 18:36:13 +03:00
PushOnly bool ` json:"push_only" `
SendEverything bool ` json:"send_everything" `
ChooseEvents bool ` json:"choose_events" `
HookEvents ` json:"events" `
2014-05-06 04:52:25 +04:00
}
2015-08-26 16:45:51 +03:00
type HookStatus int
const (
HOOK_STATUS_NONE = iota
HOOK_STATUS_SUCCEED
HOOK_STATUS_FAILED
)
2014-06-08 12:45:34 +04:00
// Webhook represents a web hook object.
2014-05-06 04:52:25 +04:00
type Webhook struct {
2015-08-26 16:45:51 +03:00
ID int64 ` xorm:"pk autoincr" `
RepoID int64
OrgID int64
URL string ` xorm:"url TEXT" `
2014-08-24 16:59:47 +04:00
ContentType HookContentType
Secret string ` xorm:"TEXT" `
Events string ` xorm:"TEXT" `
* HookEvent ` xorm:"-" `
2015-08-26 16:45:51 +03:00
IsSSL bool ` xorm:"is_ssl" `
2014-08-24 16:59:47 +04:00
IsActive bool
HookTaskType HookTaskType
2015-08-26 16:45:51 +03:00
Meta string ` xorm:"TEXT" ` // store hook-specific attributes
LastStatus HookStatus // Last delivery status
2016-03-10 03:53:30 +03:00
Created time . Time ` xorm:"-" `
CreatedUnix int64
Updated time . Time ` xorm:"-" `
UpdatedUnix int64
}
func ( w * Webhook ) BeforeInsert ( ) {
w . CreatedUnix = time . Now ( ) . UTC ( ) . Unix ( )
w . UpdatedUnix = w . CreatedUnix
}
func ( w * Webhook ) BeforeUpdate ( ) {
w . UpdatedUnix = time . Now ( ) . UTC ( ) . Unix ( )
2014-05-06 04:52:25 +04:00
}
2015-08-29 06:49:59 +03:00
func ( w * Webhook ) AfterSet ( colName string , _ xorm . Cell ) {
var err error
switch colName {
case "events" :
w . HookEvent = & HookEvent { }
if err = json . Unmarshal ( [ ] byte ( w . Events ) , w . HookEvent ) ; err != nil {
log . Error ( 3 , "Unmarshal[%d]: %v" , w . ID , err )
}
2016-03-10 03:53:30 +03:00
case "created_unix" :
w . Created = time . Unix ( w . CreatedUnix , 0 ) . Local ( )
case "updated_unix" :
w . Updated = time . Unix ( w . UpdatedUnix , 0 ) . Local ( )
2014-05-06 04:52:25 +04:00
}
}
2015-08-28 18:36:13 +03:00
func ( w * Webhook ) GetSlackHook ( ) * SlackMeta {
s := & SlackMeta { }
2014-08-24 16:59:47 +04:00
if err := json . Unmarshal ( [ ] byte ( w . Meta ) , s ) ; err != nil {
2015-08-26 16:45:51 +03:00
log . Error ( 4 , "webhook.GetSlackHook(%d): %v" , w . ID , err )
2014-08-24 16:59:47 +04:00
}
return s
}
2015-08-27 18:06:14 +03:00
// History returns history of webhook by given conditions.
func ( w * Webhook ) History ( page int ) ( [ ] * HookTask , error ) {
return HookTasks ( w . ID , page )
}
2014-06-08 12:54:52 +04:00
// UpdateEvent handles conversion from HookEvent to Events.
2014-06-08 12:45:34 +04:00
func ( w * Webhook ) UpdateEvent ( ) error {
2014-05-06 05:36:08 +04:00
data , err := json . Marshal ( w . HookEvent )
2014-05-06 04:52:25 +04:00
w . Events = string ( data )
return err
}
2015-08-28 18:36:13 +03:00
// HasCreateEvent returns true if hook enabled create event.
func ( w * Webhook ) HasCreateEvent ( ) bool {
return w . SendEverything ||
( w . ChooseEvents && w . HookEvents . Create )
}
2014-12-07 04:22:48 +03:00
// HasPushEvent returns true if hook enabled push event.
2014-05-06 19:50:31 +04:00
func ( w * Webhook ) HasPushEvent ( ) bool {
2015-08-28 18:36:13 +03:00
return w . PushOnly || w . SendEverything ||
( w . ChooseEvents && w . HookEvents . Push )
2014-05-06 19:50:31 +04:00
}
2015-08-29 06:49:59 +03:00
func ( w * Webhook ) EventsArray ( ) [ ] string {
events := make ( [ ] string , 0 , 2 )
if w . HasCreateEvent ( ) {
events = append ( events , "create" )
}
if w . HasPushEvent ( ) {
events = append ( events , "push" )
}
return events
}
2014-06-08 12:45:34 +04:00
// CreateWebhook creates a new web hook.
2014-05-06 04:52:25 +04:00
func CreateWebhook ( w * Webhook ) error {
2014-06-21 08:51:41 +04:00
_ , err := x . Insert ( w )
2014-05-06 04:52:25 +04:00
return err
}
2015-08-27 18:06:14 +03:00
// GetWebhookByID returns webhook by given ID.
func GetWebhookByID ( id int64 ) ( * Webhook , error ) {
w := new ( Webhook )
has , err := x . Id ( id ) . Get ( w )
2014-05-06 05:36:08 +04:00
if err != nil {
return nil , err
} else if ! has {
2015-08-27 18:06:14 +03:00
return nil , ErrWebhookNotExist { id }
2014-05-06 05:36:08 +04:00
}
return w , nil
}
2015-08-28 18:36:13 +03:00
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
func GetActiveWebhooksByRepoID ( repoID int64 ) ( ws [ ] * Webhook , err error ) {
err = x . Where ( "repo_id=?" , repoID ) . And ( "is_active=?" , true ) . Find ( & ws )
2014-05-06 19:50:31 +04:00
return ws , err
}
2015-11-19 05:21:47 +03:00
// GetWebhooksByRepoID returns all webhooks of repository.
func GetWebhooksByRepoID ( repoID int64 ) ( ws [ ] * Webhook , err error ) {
2015-08-26 16:45:51 +03:00
err = x . Find ( & ws , & Webhook { RepoID : repoID } )
2014-05-06 04:52:25 +04:00
return ws , err
}
2014-05-06 05:36:08 +04:00
2014-06-08 12:45:34 +04:00
// UpdateWebhook updates information of webhook.
func UpdateWebhook ( w * Webhook ) error {
2015-08-26 16:45:51 +03:00
_ , err := x . Id ( w . ID ) . AllCols ( ) . Update ( w )
2014-06-08 12:45:34 +04:00
return err
}
2014-05-06 05:36:08 +04:00
// DeleteWebhook deletes webhook of repository.
2015-08-26 16:45:51 +03:00
func DeleteWebhook ( id int64 ) ( err error ) {
sess := x . NewSession ( )
defer sessionRelease ( sess )
if err = sess . Begin ( ) ; err != nil {
return err
}
if _ , err = sess . Delete ( & Webhook { ID : id } ) ; err != nil {
return err
} else if _ , err = sess . Delete ( & HookTask { HookID : id } ) ; err != nil {
return err
}
return sess . Commit ( )
2014-05-06 05:36:08 +04:00
}
2014-06-08 12:45:34 +04:00
2014-09-04 15:17:00 +04:00
// GetWebhooksByOrgId returns all webhooks for an organization.
2015-08-26 16:45:51 +03:00
func GetWebhooksByOrgId ( orgID int64 ) ( ws [ ] * Webhook , err error ) {
err = x . Find ( & ws , & Webhook { OrgID : orgID } )
2014-09-04 15:17:00 +04:00
return ws , err
}
2015-08-28 18:36:13 +03:00
// GetActiveWebhooksByOrgID returns all active webhooks for an organization.
func GetActiveWebhooksByOrgID ( orgID int64 ) ( ws [ ] * Webhook , err error ) {
err = x . Where ( "org_id=?" , orgID ) . And ( "is_active=?" , true ) . Find ( & ws )
2014-09-04 15:17:00 +04:00
return ws , err
}
2014-06-08 12:45:34 +04:00
// ___ ___ __ ___________ __
// / | \ ____ ____ | | _\__ ___/____ _____| | __
// / ~ \/ _ \ / _ \| |/ / | | \__ \ / ___/ |/ /
// \ Y ( <_> | <_> ) < | | / __ \_\___ \| <
// \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \
// \/ \/ \/ \/ \/
type HookTaskType int
const (
2014-08-24 16:59:47 +04:00
GOGS HookTaskType = iota + 1
SLACK
2014-06-08 12:45:34 +04:00
)
2014-11-13 20:57:00 +03:00
var hookTaskTypes = map [ string ] HookTaskType {
"gogs" : GOGS ,
"slack" : SLACK ,
}
// ToHookTaskType returns HookTaskType by given name.
func ToHookTaskType ( name string ) HookTaskType {
return hookTaskTypes [ name ]
}
2014-11-13 10:32:18 +03:00
func ( t HookTaskType ) Name ( ) string {
switch t {
case GOGS :
return "gogs"
case SLACK :
return "slack"
}
return ""
}
2014-11-13 20:57:00 +03:00
// IsValidHookTaskType returns true if given name is a valid hook task type.
func IsValidHookTaskType ( name string ) bool {
_ , ok := hookTaskTypes [ name ]
return ok
}
2014-08-10 02:40:10 +04:00
type HookEventType string
const (
2015-08-28 18:36:13 +03:00
HOOK_EVENT_CREATE HookEventType = "create"
HOOK_EVENT_PUSH HookEventType = "push"
2014-08-10 02:40:10 +04:00
)
2015-08-27 18:06:14 +03:00
// HookRequest represents hook task request information.
type HookRequest struct {
Headers map [ string ] string ` json:"headers" `
}
// HookResponse represents hook task response information.
type HookResponse struct {
Status int ` json:"status" `
Headers map [ string ] string ` json:"headers" `
Body string ` json:"body" `
}
2014-06-08 12:54:52 +04:00
// HookTask represents a hook task.
2014-06-08 12:45:34 +04:00
type HookTask struct {
2015-08-27 18:06:14 +03:00
ID int64 ` xorm:"pk autoincr" `
RepoID int64 ` xorm:"INDEX" `
HookID int64
UUID string
Type HookTaskType
2016-01-27 03:38:07 +03:00
URL string ` xorm:"TEXT" `
2015-08-28 18:36:13 +03:00
api . Payloader ` xorm:"-" `
2015-08-27 18:06:14 +03:00
PayloadContent string ` xorm:"TEXT" `
ContentType HookContentType
EventType HookEventType
IsSSL bool
IsDelivered bool
Delivered int64
DeliveredString string ` xorm:"-" `
// History info.
IsSucceed bool
RequestContent string ` xorm:"TEXT" `
RequestInfo * HookRequest ` xorm:"-" `
ResponseContent string ` xorm:"TEXT" `
ResponseInfo * HookResponse ` xorm:"-" `
}
func ( t * HookTask ) BeforeUpdate ( ) {
if t . RequestInfo != nil {
t . RequestContent = t . MarshalJSON ( t . RequestInfo )
}
if t . ResponseInfo != nil {
t . ResponseContent = t . MarshalJSON ( t . ResponseInfo )
}
}
func ( t * HookTask ) AfterSet ( colName string , _ xorm . Cell ) {
var err error
switch colName {
case "delivered" :
t . DeliveredString = time . Unix ( 0 , t . Delivered ) . Format ( "2006-01-02 15:04:05 MST" )
case "request_content" :
if len ( t . RequestContent ) == 0 {
return
}
t . RequestInfo = & HookRequest { }
if err = json . Unmarshal ( [ ] byte ( t . RequestContent ) , t . RequestInfo ) ; err != nil {
log . Error ( 3 , "Unmarshal[%d]: %v" , t . ID , err )
}
case "response_content" :
if len ( t . ResponseContent ) == 0 {
return
}
t . ResponseInfo = & HookResponse { }
if err = json . Unmarshal ( [ ] byte ( t . ResponseContent ) , t . ResponseInfo ) ; err != nil {
2015-12-05 21:24:13 +03:00
log . Error ( 3 , "Unmarshal [%d]: %v" , t . ID , err )
2015-08-27 18:06:14 +03:00
}
}
}
func ( t * HookTask ) MarshalJSON ( v interface { } ) string {
p , err := json . Marshal ( v )
if err != nil {
2015-12-05 21:24:13 +03:00
log . Error ( 3 , "Marshal [%d]: %v" , t . ID , err )
2015-08-27 18:06:14 +03:00
}
return string ( p )
}
// HookTasks returns a list of hook tasks by given conditions.
func HookTasks ( hookID int64 , page int ) ( [ ] * HookTask , error ) {
tasks := make ( [ ] * HookTask , 0 , setting . Webhook . PagingNum )
2015-08-28 18:36:13 +03:00
return tasks , x . Limit ( setting . Webhook . PagingNum , ( page - 1 ) * setting . Webhook . PagingNum ) . Where ( "hook_id=?" , hookID ) . Desc ( "id" ) . Find ( & tasks )
2014-06-08 12:45:34 +04:00
}
// CreateHookTask creates a new hook task,
// it handles conversion from Payload to PayloadContent.
func CreateHookTask ( t * HookTask ) error {
2015-08-28 18:36:13 +03:00
data , err := t . Payloader . JSONPayload ( )
2014-06-08 12:45:34 +04:00
if err != nil {
return err
}
2016-02-21 02:13:12 +03:00
t . UUID = gouuid . NewV4 ( ) . String ( )
2014-06-08 12:45:34 +04:00
t . PayloadContent = string ( data )
2014-06-21 08:51:41 +04:00
_ , err = x . Insert ( t )
2014-06-08 12:45:34 +04:00
return err
}
// UpdateHookTask updates information of hook task.
func UpdateHookTask ( t * HookTask ) error {
2015-07-25 16:32:04 +03:00
_ , err := x . Id ( t . ID ) . AllCols ( ) . Update ( t )
2014-06-08 12:45:34 +04:00
return err
}
2015-08-28 18:36:13 +03:00
// PrepareWebhooks adds new webhooks to task queue for given payload.
func PrepareWebhooks ( repo * Repository , event HookEventType , p api . Payloader ) error {
if err := repo . GetOwner ( ) ; err != nil {
return fmt . Errorf ( "GetOwner: %v" , err )
}
ws , err := GetActiveWebhooksByRepoID ( repo . ID )
if err != nil {
return fmt . Errorf ( "GetActiveWebhooksByRepoID: %v" , err )
}
// check if repo belongs to org and append additional webhooks
if repo . Owner . IsOrganization ( ) {
// get hooks for org
orgws , err := GetActiveWebhooksByOrgID ( repo . OwnerID )
if err != nil {
return fmt . Errorf ( "GetActiveWebhooksByOrgID: %v" , err )
}
ws = append ( ws , orgws ... )
}
if len ( ws ) == 0 {
return nil
}
2016-02-10 23:21:39 +03:00
var payloader api . Payloader
2015-08-28 18:36:13 +03:00
for _ , w := range ws {
switch event {
case HOOK_EVENT_CREATE :
if ! w . HasCreateEvent ( ) {
continue
}
case HOOK_EVENT_PUSH :
if ! w . HasPushEvent ( ) {
continue
}
}
2016-02-10 23:21:39 +03:00
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
2015-08-28 18:36:13 +03:00
switch w . HookTaskType {
case SLACK :
2016-02-10 23:21:39 +03:00
payloader , err = GetSlackPayload ( p , event , w . Meta )
2015-08-28 18:36:13 +03:00
if err != nil {
return fmt . Errorf ( "GetSlackPayload: %v" , err )
}
default :
p . SetSecret ( w . Secret )
2016-02-10 23:21:39 +03:00
payloader = p
2015-08-28 18:36:13 +03:00
}
if err = CreateHookTask ( & HookTask {
RepoID : repo . ID ,
HookID : w . ID ,
Type : w . HookTaskType ,
URL : w . URL ,
2016-02-10 23:21:39 +03:00
Payloader : payloader ,
2015-08-28 18:36:13 +03:00
ContentType : w . ContentType ,
EventType : HOOK_EVENT_PUSH ,
IsSSL : w . IsSSL ,
} ) ; err != nil {
return fmt . Errorf ( "CreateHookTask: %v" , err )
}
}
return nil
}
2015-10-24 10:36:47 +03:00
// UniqueQueue represents a queue that guarantees only one instance of same ID is in the line.
type UniqueQueue struct {
lock sync . Mutex
ids map [ string ] bool
2014-10-10 03:01:22 +04:00
2015-10-24 10:36:47 +03:00
queue chan string
2015-07-25 16:32:04 +03:00
}
2015-10-24 10:36:47 +03:00
func ( q * UniqueQueue ) Queue ( ) <- chan string {
return q . queue
}
func NewUniqueQueue ( queueLength int ) * UniqueQueue {
if queueLength <= 0 {
queueLength = 100
}
return & UniqueQueue {
ids : make ( map [ string ] bool ) ,
queue : make ( chan string , queueLength ) ,
}
}
func ( q * UniqueQueue ) Remove ( id interface { } ) {
2015-07-25 16:32:04 +03:00
q . lock . Lock ( )
defer q . lock . Unlock ( )
2015-10-24 10:36:47 +03:00
delete ( q . ids , com . ToStr ( id ) )
2015-07-25 16:32:04 +03:00
}
2015-10-24 21:48:11 +03:00
func ( q * UniqueQueue ) AddFunc ( id interface { } , fn func ( ) ) {
2015-10-24 10:36:47 +03:00
newid := com . ToStr ( id )
if q . Exist ( id ) {
2014-10-10 03:01:22 +04:00
return
}
2015-10-24 10:36:47 +03:00
q . lock . Lock ( )
q . ids [ newid ] = true
2015-10-24 21:48:11 +03:00
if fn != nil {
fn ( )
}
2015-07-25 16:32:04 +03:00
q . lock . Unlock ( )
2015-10-24 10:36:47 +03:00
q . queue <- newid
2015-07-25 16:32:04 +03:00
}
2014-10-10 03:01:22 +04:00
2015-10-24 21:48:11 +03:00
func ( q * UniqueQueue ) Add ( id interface { } ) {
q . AddFunc ( id , nil )
}
2015-10-24 10:36:47 +03:00
func ( q * UniqueQueue ) Exist ( id interface { } ) bool {
q . lock . Lock ( )
defer q . lock . Unlock ( )
return q . ids [ com . ToStr ( id ) ]
2015-07-25 16:32:04 +03:00
}
2015-10-24 10:36:47 +03:00
var HookQueue = NewUniqueQueue ( setting . Webhook . QueueLength )
2015-07-25 16:32:04 +03:00
2015-10-24 10:36:47 +03:00
func ( t * HookTask ) deliver ( ) {
2015-08-27 18:06:14 +03:00
t . IsDelivered = true
2015-02-11 05:06:59 +03:00
timeout := time . Duration ( setting . Webhook . DeliverTimeout ) * time . Second
2015-08-27 18:06:14 +03:00
req := httplib . Post ( t . URL ) . SetTimeout ( timeout , timeout ) .
Header ( "X-Gogs-Delivery" , t . UUID ) .
2015-07-25 16:32:04 +03:00
Header ( "X-Gogs-Event" , string ( t . EventType ) ) .
SetTLSClientConfig ( & tls . Config { InsecureSkipVerify : setting . Webhook . SkipTLSVerify } )
2014-06-08 12:45:34 +04:00
2015-07-25 16:32:04 +03:00
switch t . ContentType {
case JSON :
req = req . Header ( "Content-Type" , "application/json" ) . Body ( t . PayloadContent )
case FORM :
req . Param ( "payload" , t . PayloadContent )
}
2014-08-10 02:40:10 +04:00
2015-08-27 18:06:14 +03:00
// Record delivery information.
t . RequestInfo = & HookRequest {
Headers : map [ string ] string { } ,
}
for k , vals := range req . Headers ( ) {
t . RequestInfo . Headers [ k ] = strings . Join ( vals , "," )
}
2015-07-25 16:32:04 +03:00
2015-08-27 18:06:14 +03:00
t . ResponseInfo = & HookResponse {
Headers : map [ string ] string { } ,
}
defer func ( ) {
t . Delivered = time . Now ( ) . UTC ( ) . UnixNano ( )
if t . IsSucceed {
log . Trace ( "Hook delivered: %s" , t . UUID )
2015-12-05 21:50:43 +03:00
} else {
log . Trace ( "Hook delivery failed: %s" , t . UUID )
2015-07-25 16:32:04 +03:00
}
2015-08-27 18:06:14 +03:00
// Update webhook last delivery status.
w , err := GetWebhookByID ( t . HookID )
if err != nil {
log . Error ( 5 , "GetWebhookByID: %v" , err )
return
}
if t . IsSucceed {
w . LastStatus = HOOK_STATUS_SUCCEED
} else {
w . LastStatus = HOOK_STATUS_FAILED
2015-07-25 16:32:04 +03:00
}
2015-08-27 18:06:14 +03:00
if err = UpdateWebhook ( w ) ; err != nil {
log . Error ( 5 , "UpdateWebhook: %v" , err )
return
}
} ( )
resp , err := req . Response ( )
if err != nil {
t . ResponseInfo . Body = fmt . Sprintf ( "Delivery: %v" , err )
return
2015-07-25 16:32:04 +03:00
}
2015-08-27 18:06:14 +03:00
defer resp . Body . Close ( )
2014-08-10 02:40:10 +04:00
2015-08-27 18:06:14 +03:00
// Status code is 20x can be seen as succeed.
t . IsSucceed = resp . StatusCode / 100 == 2
t . ResponseInfo . Status = resp . StatusCode
for k , vals := range resp . Header {
t . ResponseInfo . Headers [ k ] = strings . Join ( vals , "," )
}
p , err := ioutil . ReadAll ( resp . Body )
if err != nil {
t . ResponseInfo . Body = fmt . Sprintf ( "read body: %s" , err )
return
}
t . ResponseInfo . Body = string ( p )
switch t . Type {
case SLACK :
if t . ResponseInfo . Body != "ok" {
log . Error ( 5 , "slack failed with: %s" , t . ResponseInfo . Body )
t . IsSucceed = false
}
2015-07-25 16:32:04 +03:00
}
}
2014-06-08 12:45:34 +04:00
2015-07-25 16:32:04 +03:00
// DeliverHooks checks and delivers undelivered hooks.
2015-10-24 10:36:47 +03:00
// TODO: shoot more hooks at same time.
2015-07-25 16:32:04 +03:00
func DeliverHooks ( ) {
tasks := make ( [ ] * HookTask , 0 , 10 )
x . Where ( "is_delivered=?" , false ) . Iterate ( new ( HookTask ) ,
func ( idx int , bean interface { } ) error {
t := bean . ( * HookTask )
2015-10-24 10:36:47 +03:00
t . deliver ( )
2015-07-25 16:32:04 +03:00
tasks = append ( tasks , t )
2014-06-08 12:45:34 +04:00
return nil
} )
2014-09-13 02:58:24 +04:00
// Update hook task status.
for _ , t := range tasks {
if err := UpdateHookTask ( t ) ; err != nil {
2015-12-05 21:24:13 +03:00
log . Error ( 4 , "UpdateHookTask [%d]: %v" , t . ID , err )
2015-07-25 16:32:04 +03:00
}
}
// Start listening on new hook requests.
2015-10-24 10:36:47 +03:00
for repoID := range HookQueue . Queue ( ) {
2015-12-05 21:24:13 +03:00
log . Trace ( "DeliverHooks [%v]: processing delivery hooks" , repoID )
2015-10-24 10:36:47 +03:00
HookQueue . Remove ( repoID )
2015-07-25 16:32:04 +03:00
tasks = make ( [ ] * HookTask , 0 , 5 )
if err := x . Where ( "repo_id=? AND is_delivered=?" , repoID , false ) . Find ( & tasks ) ; err != nil {
2015-12-05 21:24:13 +03:00
log . Error ( 4 , "Get repository [%d] hook tasks: %v" , repoID , err )
2015-07-25 16:32:04 +03:00
continue
}
for _ , t := range tasks {
2015-10-24 10:36:47 +03:00
t . deliver ( )
2015-07-25 16:32:04 +03:00
if err := UpdateHookTask ( t ) ; err != nil {
2015-12-05 21:24:13 +03:00
log . Error ( 4 , "UpdateHookTask [%d]: %v" , t . ID , err )
2015-10-24 10:36:47 +03:00
continue
2015-07-25 16:32:04 +03:00
}
2014-09-13 02:58:24 +04:00
}
}
2014-06-08 12:45:34 +04:00
}
2015-07-25 16:32:04 +03:00
func InitDeliverHooks ( ) {
go DeliverHooks ( )
}