github.com/line/line-bot-sdk-go/v7@v7.21.0/linebot/event.go (about)

     1  // Copyright 2016 LINE Corporation
     2  //
     3  // LINE Corporation licenses this file to you under the Apache License,
     4  // version 2.0 (the "License"); you may not use this file except in compliance
     5  // with the License. You may obtain a copy of the License at:
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package linebot
    16  
    17  import (
    18  	"encoding/hex"
    19  	"encoding/json"
    20  	"time"
    21  )
    22  
    23  // EventType type
    24  type EventType string
    25  
    26  // EventType constants
    27  const (
    28  	EventTypeMessage           EventType = "message"
    29  	EventTypeFollow            EventType = "follow"
    30  	EventTypeUnfollow          EventType = "unfollow"
    31  	EventTypeJoin              EventType = "join"
    32  	EventTypeLeave             EventType = "leave"
    33  	EventTypeMemberJoined      EventType = "memberJoined"
    34  	EventTypeMemberLeft        EventType = "memberLeft"
    35  	EventTypePostback          EventType = "postback"
    36  	EventTypeBeacon            EventType = "beacon"
    37  	EventTypeAccountLink       EventType = "accountLink"
    38  	EventTypeThings            EventType = "things"
    39  	EventTypeUnsend            EventType = "unsend"
    40  	EventTypeVideoPlayComplete EventType = "videoPlayComplete"
    41  )
    42  
    43  // EventMode type
    44  type EventMode string
    45  
    46  // EventMode constants
    47  const (
    48  	EventModeActive  EventMode = "active"
    49  	EventModeStandby EventMode = "standby"
    50  )
    51  
    52  // EventSourceType type
    53  type EventSourceType string
    54  
    55  // EventSourceType constants
    56  const (
    57  	EventSourceTypeUser  EventSourceType = "user"
    58  	EventSourceTypeGroup EventSourceType = "group"
    59  	EventSourceTypeRoom  EventSourceType = "room"
    60  )
    61  
    62  // EventSource type
    63  type EventSource struct {
    64  	Type    EventSourceType `json:"type"`
    65  	UserID  string          `json:"userId,omitempty"`
    66  	GroupID string          `json:"groupId,omitempty"`
    67  	RoomID  string          `json:"roomId,omitempty"`
    68  }
    69  
    70  // Params type
    71  type Params struct {
    72  	Date               string `json:"date,omitempty"`
    73  	Time               string `json:"time,omitempty"`
    74  	Datetime           string `json:"datetime,omitempty"`
    75  	NewRichMenuAliasID string `json:"newRichMenuAliasId,omitempty"`
    76  	Status             string `json:"status,omitempty"`
    77  }
    78  
    79  // Members type
    80  type Members struct {
    81  	Members []EventSource `json:"members"`
    82  }
    83  
    84  // Postback type
    85  type Postback struct {
    86  	Data   string  `json:"data"`
    87  	Params *Params `json:"params,omitempty"`
    88  }
    89  
    90  // BeaconEventType type
    91  type BeaconEventType string
    92  
    93  // BeaconEventType constants
    94  const (
    95  	BeaconEventTypeEnter  BeaconEventType = "enter"
    96  	BeaconEventTypeLeave  BeaconEventType = "leave"
    97  	BeaconEventTypeBanner BeaconEventType = "banner"
    98  	BeaconEventTypeStay   BeaconEventType = "stay"
    99  )
   100  
   101  // Beacon type
   102  type Beacon struct {
   103  	Hwid          string
   104  	Type          BeaconEventType
   105  	DeviceMessage []byte
   106  }
   107  
   108  // AccountLinkResult type
   109  type AccountLinkResult string
   110  
   111  // AccountLinkResult constants
   112  const (
   113  	AccountLinkResultOK     AccountLinkResult = "ok"
   114  	AccountLinkResultFailed AccountLinkResult = "failed"
   115  )
   116  
   117  // AccountLink type
   118  type AccountLink struct {
   119  	Result AccountLinkResult
   120  	Nonce  string
   121  }
   122  
   123  // ThingsResult type
   124  type ThingsResult struct {
   125  	ScenarioID             string
   126  	Revision               int
   127  	StartTime              int64
   128  	EndTime                int64
   129  	ResultCode             ThingsResultCode
   130  	ActionResults          []*ThingsActionResult
   131  	BLENotificationPayload []byte
   132  	ErrorReason            string
   133  }
   134  
   135  // ThingsResultCode type
   136  type ThingsResultCode string
   137  
   138  // ThingsResultCode constants
   139  const (
   140  	ThingsResultCodeSuccess      ThingsResultCode = "success"
   141  	ThingsResultCodeGattError    ThingsResultCode = "gatt_error"
   142  	ThingsResultCodeRuntimeError ThingsResultCode = "runtime_error"
   143  )
   144  
   145  // ThingsActionResult type
   146  type ThingsActionResult struct {
   147  	Type ThingsActionResultType
   148  	Data []byte
   149  }
   150  
   151  // ThingsActionResultType type
   152  type ThingsActionResultType string
   153  
   154  // ThingsActionResultType constants
   155  const (
   156  	ThingsActionResultTypeBinary ThingsActionResultType = "binary"
   157  	ThingsActionResultTypeVoid   ThingsActionResultType = "void"
   158  )
   159  
   160  // Things type
   161  type Things struct {
   162  	DeviceID string
   163  	Type     string
   164  	Result   *ThingsResult
   165  }
   166  
   167  // Unsend type
   168  type Unsend struct {
   169  	MessageID string `json:"messageId"`
   170  }
   171  
   172  // VideoPlayComplete type
   173  type VideoPlayComplete struct {
   174  	TrackingID string `json:"trackingId"`
   175  }
   176  
   177  // StickerResourceType type
   178  type StickerResourceType string
   179  
   180  // StickerResourceType constants
   181  const (
   182  	StickerResourceTypeStatic         StickerResourceType = "STATIC"
   183  	StickerResourceTypeAnimation      StickerResourceType = "ANIMATION"
   184  	StickerResourceTypeSound          StickerResourceType = "SOUND"
   185  	StickerResourceTypeAnimationSound StickerResourceType = "ANIMATION_SOUND"
   186  	StickerResourceTypePerStickerText StickerResourceType = "MESSAGE"
   187  	StickerResourceTypePopup          StickerResourceType = "POPUP"
   188  	StickerResourceTypePopupSound     StickerResourceType = "POPUP_SOUND"
   189  	StickerResourceTypeNameText       StickerResourceType = "CUSTOM"
   190  )
   191  
   192  // DeliveryContext type
   193  type DeliveryContext struct {
   194  	IsRedelivery bool `json:"isRedelivery"`
   195  }
   196  
   197  // Event type
   198  type Event struct {
   199  	ReplyToken        string
   200  	Type              EventType
   201  	Mode              EventMode
   202  	Timestamp         time.Time
   203  	Source            *EventSource
   204  	Message           Message
   205  	Joined            *Members
   206  	Left              *Members
   207  	Postback          *Postback
   208  	Beacon            *Beacon
   209  	AccountLink       *AccountLink
   210  	Things            *Things
   211  	Members           []*EventSource
   212  	Unsend            *Unsend
   213  	VideoPlayComplete *VideoPlayComplete
   214  	WebhookEventID    string
   215  	DeliveryContext   DeliveryContext
   216  }
   217  
   218  type rawEvent struct {
   219  	ReplyToken        string               `json:"replyToken,omitempty"`
   220  	Type              EventType            `json:"type"`
   221  	Mode              EventMode            `json:"mode"`
   222  	Timestamp         int64                `json:"timestamp"`
   223  	Source            *EventSource         `json:"source"`
   224  	Message           *rawEventMessage     `json:"message,omitempty"`
   225  	Postback          *Postback            `json:"postback,omitempty"`
   226  	Beacon            *rawBeaconEvent      `json:"beacon,omitempty"`
   227  	AccountLink       *rawAccountLinkEvent `json:"link,omitempty"`
   228  	Joined            *rawMemberEvent      `json:"joined,omitempty"`
   229  	Left              *rawMemberEvent      `json:"left,omitempty"`
   230  	Things            *rawThingsEvent      `json:"things,omitempty"`
   231  	Unsend            *Unsend              `json:"unsend,omitempty"`
   232  	VideoPlayComplete *VideoPlayComplete   `json:"videoPlayComplete,omitempty"`
   233  	WebhookEventID    string               `json:"webhookEventId"`
   234  	DeliveryContext   DeliveryContext      `json:"deliveryContext"`
   235  }
   236  
   237  type rawMemberEvent struct {
   238  	Members []*EventSource `json:"members"`
   239  }
   240  
   241  type rawEventMessage struct {
   242  	ID                  string              `json:"id"`
   243  	Type                MessageType         `json:"type"`
   244  	Text                string              `json:"text,omitempty"`
   245  	Duration            int                 `json:"duration,omitempty"`
   246  	Title               string              `json:"title,omitempty"`
   247  	Address             string              `json:"address,omitempty"`
   248  	FileName            string              `json:"fileName,omitempty"`
   249  	FileSize            int                 `json:"fileSize,omitempty"`
   250  	Latitude            float64             `json:"latitude,omitempty"`
   251  	Longitude           float64             `json:"longitude,omitempty"`
   252  	PackageID           string              `json:"packageId,omitempty"`
   253  	StickerID           string              `json:"stickerId,omitempty"`
   254  	ContentProvider     *ContentProvider    `json:"contentProvider,omitempty"`
   255  	ImageSet            *ImageSet           `json:"imageSet,omitempty"`
   256  	StickerResourceType StickerResourceType `json:"stickerResourceType,omitempty"`
   257  	Keywords            []string            `json:"keywords,omitempty"`
   258  	Emojis              []*Emoji            `json:"emojis,omitempty"`
   259  	Mention             *Mention            `json:"mention,omitempty"`
   260  }
   261  
   262  type rawBeaconEvent struct {
   263  	Hwid string          `json:"hwid"`
   264  	Type BeaconEventType `json:"type"`
   265  	DM   string          `json:"dm,omitempty"`
   266  }
   267  
   268  type rawAccountLinkEvent struct {
   269  	Result AccountLinkResult `json:"result"`
   270  	Nonce  string            `json:"nonce"`
   271  }
   272  
   273  type rawThingsResult struct {
   274  	ScenarioID             string                   `json:"scenarioId"`
   275  	Revision               int                      `json:"revision"`
   276  	StartTime              int64                    `json:"startTime"`
   277  	EndTime                int64                    `json:"endTime"`
   278  	ResultCode             ThingsResultCode         `json:"resultCode"`
   279  	ActionResults          []*rawThingsActionResult `json:"actionResults"`
   280  	BLENotificationPayload string                   `json:"bleNotificationPayload,omitempty"`
   281  	ErrorReason            string                   `json:"errorReason,omitempty"`
   282  }
   283  
   284  type rawThingsActionResult struct {
   285  	Type ThingsActionResultType `json:"type,omitempty"`
   286  	Data string                 `json:"data,omitempty"`
   287  }
   288  
   289  type rawThingsEvent struct {
   290  	DeviceID string           `json:"deviceId"`
   291  	Type     string           `json:"type"`
   292  	Result   *rawThingsResult `json:"result,omitempty"`
   293  }
   294  
   295  const (
   296  	milliSecPerSec     = int64(time.Second / time.Millisecond)
   297  	nanoSecPerMilliSec = int64(time.Millisecond / time.Nanosecond)
   298  )
   299  
   300  // MarshalJSON method of Event
   301  func (e *Event) MarshalJSON() ([]byte, error) {
   302  	raw := rawEvent{
   303  		ReplyToken:        e.ReplyToken,
   304  		Type:              e.Type,
   305  		Mode:              e.Mode,
   306  		Timestamp:         e.Timestamp.Unix()*milliSecPerSec + int64(e.Timestamp.Nanosecond())/int64(time.Millisecond),
   307  		Source:            e.Source,
   308  		Postback:          e.Postback,
   309  		Unsend:            e.Unsend,
   310  		VideoPlayComplete: e.VideoPlayComplete,
   311  		WebhookEventID:    e.WebhookEventID,
   312  		DeliveryContext:   e.DeliveryContext,
   313  	}
   314  	if e.Beacon != nil {
   315  		raw.Beacon = &rawBeaconEvent{
   316  			Hwid: e.Beacon.Hwid,
   317  			Type: e.Beacon.Type,
   318  			DM:   hex.EncodeToString(e.Beacon.DeviceMessage),
   319  		}
   320  	}
   321  	if e.AccountLink != nil {
   322  		raw.AccountLink = &rawAccountLinkEvent{
   323  			Result: e.AccountLink.Result,
   324  			Nonce:  e.AccountLink.Nonce,
   325  		}
   326  	}
   327  
   328  	switch e.Type {
   329  	case EventTypeMemberJoined:
   330  		raw.Joined = &rawMemberEvent{
   331  			Members: e.Members,
   332  		}
   333  	case EventTypeMemberLeft:
   334  		raw.Left = &rawMemberEvent{
   335  			Members: e.Members,
   336  		}
   337  	case EventTypeThings:
   338  		raw.Things = &rawThingsEvent{
   339  			DeviceID: e.Things.DeviceID,
   340  			Type:     e.Things.Type,
   341  		}
   342  		if e.Things.Result != nil {
   343  			raw.Things.Result = &rawThingsResult{
   344  				ScenarioID: e.Things.Result.ScenarioID,
   345  				Revision:   e.Things.Result.Revision,
   346  				StartTime:  e.Things.Result.StartTime,
   347  				EndTime:    e.Things.Result.EndTime,
   348  				ResultCode: e.Things.Result.ResultCode,
   349  
   350  				BLENotificationPayload: string(e.Things.Result.BLENotificationPayload),
   351  				ErrorReason:            e.Things.Result.ErrorReason,
   352  			}
   353  			if e.Things.Result.ActionResults != nil {
   354  				raw.Things.Result.ActionResults = make([]*rawThingsActionResult, len(e.Things.Result.ActionResults))
   355  			}
   356  			for i := range e.Things.Result.ActionResults {
   357  				raw.Things.Result.ActionResults[i] = &rawThingsActionResult{
   358  					Type: e.Things.Result.ActionResults[i].Type,
   359  					Data: string(e.Things.Result.ActionResults[i].Data),
   360  				}
   361  			}
   362  		}
   363  	}
   364  
   365  	switch m := e.Message.(type) {
   366  	case *TextMessage:
   367  		raw.Message = &rawEventMessage{
   368  			Type:    MessageTypeText,
   369  			ID:      m.ID,
   370  			Text:    m.Text,
   371  			Emojis:  m.Emojis,
   372  			Mention: m.Mention,
   373  		}
   374  	case *ImageMessage:
   375  		raw.Message = &rawEventMessage{
   376  			Type:            MessageTypeImage,
   377  			ID:              m.ID,
   378  			ContentProvider: m.ContentProvider,
   379  			ImageSet:        m.ImageSet,
   380  		}
   381  	case *VideoMessage:
   382  		raw.Message = &rawEventMessage{
   383  			Type:            MessageTypeVideo,
   384  			ID:              m.ID,
   385  			Duration:        m.Duration,
   386  			ContentProvider: m.ContentProvider,
   387  		}
   388  	case *AudioMessage:
   389  		raw.Message = &rawEventMessage{
   390  			Type:            MessageTypeAudio,
   391  			ID:              m.ID,
   392  			Duration:        m.Duration,
   393  			ContentProvider: m.ContentProvider,
   394  		}
   395  	case *FileMessage:
   396  		raw.Message = &rawEventMessage{
   397  			Type:     MessageTypeFile,
   398  			ID:       m.ID,
   399  			FileName: m.FileName,
   400  			FileSize: m.FileSize,
   401  		}
   402  	case *LocationMessage:
   403  		raw.Message = &rawEventMessage{
   404  			Type:      MessageTypeLocation,
   405  			ID:        m.ID,
   406  			Title:     m.Title,
   407  			Address:   m.Address,
   408  			Latitude:  m.Latitude,
   409  			Longitude: m.Longitude,
   410  		}
   411  	case *StickerMessage:
   412  		raw.Message = &rawEventMessage{
   413  			Type:                MessageTypeSticker,
   414  			ID:                  m.ID,
   415  			PackageID:           m.PackageID,
   416  			StickerID:           m.StickerID,
   417  			StickerResourceType: m.StickerResourceType,
   418  			Keywords:            m.Keywords,
   419  			Text:                m.Text,
   420  		}
   421  	}
   422  	return json.Marshal(&raw)
   423  }
   424  
   425  // UnmarshalJSON method of Event
   426  func (e *Event) UnmarshalJSON(body []byte) (err error) {
   427  	rawEvent := rawEvent{}
   428  	if err = json.Unmarshal(body, &rawEvent); err != nil {
   429  		return
   430  	}
   431  
   432  	e.ReplyToken = rawEvent.ReplyToken
   433  	e.Type = rawEvent.Type
   434  	e.Mode = rawEvent.Mode
   435  	e.Timestamp = time.Unix(rawEvent.Timestamp/milliSecPerSec, (rawEvent.Timestamp%milliSecPerSec)*nanoSecPerMilliSec).UTC()
   436  	e.Source = rawEvent.Source
   437  	e.WebhookEventID = rawEvent.WebhookEventID
   438  	e.DeliveryContext = rawEvent.DeliveryContext
   439  
   440  	switch rawEvent.Type {
   441  	case EventTypeMessage:
   442  		switch rawEvent.Message.Type {
   443  		case MessageTypeText:
   444  			e.Message = &TextMessage{
   445  				ID:      rawEvent.Message.ID,
   446  				Text:    rawEvent.Message.Text,
   447  				Emojis:  rawEvent.Message.Emojis,
   448  				Mention: rawEvent.Message.Mention,
   449  			}
   450  		case MessageTypeImage:
   451  			e.Message = &ImageMessage{
   452  				ID:              rawEvent.Message.ID,
   453  				ContentProvider: rawEvent.Message.ContentProvider,
   454  				ImageSet:        rawEvent.Message.ImageSet,
   455  			}
   456  		case MessageTypeVideo:
   457  			e.Message = &VideoMessage{
   458  				ID:              rawEvent.Message.ID,
   459  				Duration:        rawEvent.Message.Duration,
   460  				ContentProvider: rawEvent.Message.ContentProvider,
   461  			}
   462  		case MessageTypeAudio:
   463  			e.Message = &AudioMessage{
   464  				ID:              rawEvent.Message.ID,
   465  				Duration:        rawEvent.Message.Duration,
   466  				ContentProvider: rawEvent.Message.ContentProvider,
   467  			}
   468  		case MessageTypeFile:
   469  			e.Message = &FileMessage{
   470  				ID:       rawEvent.Message.ID,
   471  				FileName: rawEvent.Message.FileName,
   472  				FileSize: rawEvent.Message.FileSize,
   473  			}
   474  		case MessageTypeLocation:
   475  			e.Message = &LocationMessage{
   476  				ID:        rawEvent.Message.ID,
   477  				Title:     rawEvent.Message.Title,
   478  				Address:   rawEvent.Message.Address,
   479  				Latitude:  rawEvent.Message.Latitude,
   480  				Longitude: rawEvent.Message.Longitude,
   481  			}
   482  		case MessageTypeSticker:
   483  			e.Message = &StickerMessage{
   484  				ID:                  rawEvent.Message.ID,
   485  				PackageID:           rawEvent.Message.PackageID,
   486  				StickerID:           rawEvent.Message.StickerID,
   487  				StickerResourceType: rawEvent.Message.StickerResourceType,
   488  				Keywords:            rawEvent.Message.Keywords,
   489  				Text:                rawEvent.Message.Text,
   490  			}
   491  		}
   492  	case EventTypePostback:
   493  		e.Postback = rawEvent.Postback
   494  	case EventTypeBeacon:
   495  		var deviceMessage []byte
   496  		deviceMessage, err = hex.DecodeString(rawEvent.Beacon.DM)
   497  		if err != nil {
   498  			return
   499  		}
   500  		e.Beacon = &Beacon{
   501  			Hwid:          rawEvent.Beacon.Hwid,
   502  			Type:          rawEvent.Beacon.Type,
   503  			DeviceMessage: deviceMessage,
   504  		}
   505  	case EventTypeAccountLink:
   506  		e.AccountLink = &AccountLink{
   507  			Result: rawEvent.AccountLink.Result,
   508  			Nonce:  rawEvent.AccountLink.Nonce,
   509  		}
   510  	case EventTypeMemberJoined:
   511  		e.Members = rawEvent.Joined.Members
   512  	case EventTypeMemberLeft:
   513  		e.Members = rawEvent.Left.Members
   514  	case EventTypeThings:
   515  		e.Things = &Things{
   516  			Type:     rawEvent.Things.Type,
   517  			DeviceID: rawEvent.Things.DeviceID,
   518  		}
   519  		if rawEvent.Things.Result != nil {
   520  			rawResult := rawEvent.Things.Result
   521  			e.Things.Result = &ThingsResult{
   522  				ScenarioID:             rawResult.ScenarioID,
   523  				Revision:               rawResult.Revision,
   524  				StartTime:              rawResult.StartTime,
   525  				EndTime:                rawResult.EndTime,
   526  				ResultCode:             rawResult.ResultCode,
   527  				ActionResults:          make([]*ThingsActionResult, len(rawResult.ActionResults)),
   528  				BLENotificationPayload: []byte(rawResult.BLENotificationPayload),
   529  				ErrorReason:            rawResult.ErrorReason,
   530  			}
   531  			for i := range rawResult.ActionResults {
   532  				e.Things.Result.ActionResults[i] = &ThingsActionResult{
   533  					Type: rawResult.ActionResults[i].Type,
   534  					Data: []byte(rawResult.ActionResults[i].Data),
   535  				}
   536  			}
   537  		}
   538  	case EventTypeUnsend:
   539  		e.Unsend = rawEvent.Unsend
   540  	case EventTypeVideoPlayComplete:
   541  		e.VideoPlayComplete = rawEvent.VideoPlayComplete
   542  	}
   543  	return
   544  }