parent
45bf1fd63a
commit
0bc159341d
|
@ -58,7 +58,10 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
|
|||
if m.Message.EditedTimestamp != "" {
|
||||
b.Log.Debugf("Sending edit message")
|
||||
m.Content += b.GetString("EditSuffix")
|
||||
b.messageCreate(s, (*discordgo.MessageCreate)(m))
|
||||
msg := &discordgo.MessageCreate{
|
||||
Message: m.Message,
|
||||
}
|
||||
b.messageCreate(s, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
6
go.mod
6
go.mod
|
@ -5,10 +5,10 @@ require (
|
|||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/Jeffail/gabs v1.1.1 // indirect
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c
|
||||
github.com/bwmarrin/discordgo v0.19.0
|
||||
// github.com/bwmarrin/discordgo v0.19.0
|
||||
github.com/d5/tengo v1.24.3
|
||||
github.com/d5/tengo v1.24.8
|
||||
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
||||
|
@ -70,6 +70,6 @@ require (
|
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
)
|
||||
|
||||
replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40
|
||||
replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4
|
||||
|
||||
go 1.13
|
||||
|
|
12
go.sum
12
go.sum
|
@ -11,8 +11,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
|||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 h1:TO7d4rocnNFng6ZQrPe7U6WqHtK5eHEMrgrnnM/72IQ=
|
||||
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
|
||||
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a h1:umvfZW+YE+ynhYwsyheyunB/3xRK68kNFMRNUMQxzJI=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c h1:+yAllLxP+WjpuVVE1WNm0/Oigbeob9+liYEyk/v4nj8=
|
||||
github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
|
||||
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
|
||||
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
|
||||
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
|
||||
|
@ -32,8 +32,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/d5/tengo v1.24.3 h1:wp44VW7fdfzMzIDT19tT5uNeGnm2UMd6s3TLAahrwSU=
|
||||
github.com/d5/tengo v1.24.3/go.mod h1:VhLq8Q2QFhCIJO3NhvM934qOThykMqJi9y9Siqd1ocQ=
|
||||
github.com/d5/tengo v1.24.8 h1:PRJ+NWt7ae/9sSbIfThOBTkPSvNV+dwYoBAvwfNgNJY=
|
||||
github.com/d5/tengo v1.24.8/go.mod h1:VhLq8Q2QFhCIJO3NhvM934qOThykMqJi9y9Siqd1ocQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -121,8 +121,8 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
|
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
|
||||
github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40 h1:OJmjOa1ry5IZzFowLhAZ8b3bFPWFFNUbqGxs9pNqgEU=
|
||||
github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4 h1:RvH3lC4bEp+bieca+Yh5xPU8tLJgnk7ridiSwMFHrrw=
|
||||
github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k=
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
|
||||
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca h1:3ypqEpFpt6vg5Sv2xxA8/v4WiSOnWMXW7DqxTxpM4XI=
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,22 +1,94 @@
|
|||
syntax = "proto2";
|
||||
package proto;
|
||||
|
||||
message FingerprintData {
|
||||
optional string publicKey = 1;
|
||||
optional string identifier = 2;
|
||||
message HydratedQuickReplyButton {
|
||||
optional string displayText = 1;
|
||||
optional string buttonId = 2;
|
||||
}
|
||||
|
||||
message CombinedFingerprint {
|
||||
optional uint32 version = 1;
|
||||
optional FingerprintData localFingerprint = 2;
|
||||
optional FingerprintData remoteFingerprint = 3;
|
||||
message HydratedURLButton {
|
||||
optional string displayText = 1;
|
||||
optional string url = 2;
|
||||
}
|
||||
|
||||
message MessageKey {
|
||||
optional string remoteJid = 1;
|
||||
optional bool fromMe = 2;
|
||||
optional string id = 3;
|
||||
optional string participant = 4;
|
||||
message HydratedCallButton {
|
||||
optional string displayText = 1;
|
||||
optional string phoneNumber = 2;
|
||||
}
|
||||
|
||||
message HydratedTemplateButton {
|
||||
oneof hydratedButton {
|
||||
HydratedQuickReplyButton quickReplyButton = 1;
|
||||
HydratedURLButton urlButton = 2;
|
||||
HydratedCallButton callButton = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message QuickReplyButton {
|
||||
optional HighlyStructuredMessage displayText = 1;
|
||||
optional string buttonId = 2;
|
||||
}
|
||||
|
||||
message URLButton {
|
||||
optional HighlyStructuredMessage displayText = 1;
|
||||
optional HighlyStructuredMessage url = 2;
|
||||
}
|
||||
|
||||
message CallButton {
|
||||
optional HighlyStructuredMessage displayText = 1;
|
||||
optional HighlyStructuredMessage phoneNumber = 2;
|
||||
}
|
||||
|
||||
message TemplateButton {
|
||||
oneof button {
|
||||
QuickReplyButton quickReplyButton = 1;
|
||||
URLButton urlButton = 2;
|
||||
CallButton callButton = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Location {
|
||||
optional double degreesLatitude = 1;
|
||||
optional double degreesLongitude = 2;
|
||||
optional string name = 3;
|
||||
}
|
||||
|
||||
message Point {
|
||||
optional double x = 3;
|
||||
optional double y = 4;
|
||||
}
|
||||
|
||||
message InteractiveAnnotation {
|
||||
repeated Point polygonVertices = 1;
|
||||
oneof action {
|
||||
Location location = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message AdReplyInfo {
|
||||
optional string advertiserName = 1;
|
||||
enum AD_REPLY_INFO_MEDIATYPE {
|
||||
NONE = 0;
|
||||
IMAGE = 1;
|
||||
VIDEO = 2;
|
||||
}
|
||||
optional AD_REPLY_INFO_MEDIATYPE mediaType = 2;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional string caption = 17;
|
||||
}
|
||||
|
||||
message ContextInfo {
|
||||
optional string stanzaId = 1;
|
||||
optional string participant = 2;
|
||||
optional Message quotedMessage = 3;
|
||||
optional string remoteJid = 4;
|
||||
repeated string mentionedJid = 15;
|
||||
optional string conversionSource = 18;
|
||||
optional bytes conversionData = 19;
|
||||
optional uint32 conversionDelaySeconds = 20;
|
||||
optional uint32 forwardingScore = 21;
|
||||
optional bool isForwarded = 22;
|
||||
optional AdReplyInfo quotedAd = 23;
|
||||
}
|
||||
|
||||
message SenderKeyDistributionMessage {
|
||||
|
@ -36,10 +108,12 @@ message ImageMessage {
|
|||
optional bytes fileEncSha256 = 9;
|
||||
repeated InteractiveAnnotation interactiveAnnotations = 10;
|
||||
optional string directPath = 11;
|
||||
optional int64 mediaKeyTimestamp = 12;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
optional bytes firstScanSidecar = 18;
|
||||
optional uint32 firstScanLength = 19;
|
||||
optional uint32 experimentGroupId = 20;
|
||||
}
|
||||
|
||||
message ContactMessage {
|
||||
|
@ -66,7 +140,7 @@ message ExtendedTextMessage {
|
|||
optional string title = 6;
|
||||
optional fixed32 textArgb = 7;
|
||||
optional fixed32 backgroundArgb = 8;
|
||||
enum FONTTYPE {
|
||||
enum EXTENDED_TEXT_MESSAGE_FONTTYPE {
|
||||
SANS_SERIF = 0;
|
||||
SERIF = 1;
|
||||
NORICAN_REGULAR = 2;
|
||||
|
@ -74,7 +148,12 @@ message ExtendedTextMessage {
|
|||
BEBASNEUE_REGULAR = 4;
|
||||
OSWALD_HEAVY = 5;
|
||||
}
|
||||
optional FONTTYPE font = 9;
|
||||
optional EXTENDED_TEXT_MESSAGE_FONTTYPE font = 9;
|
||||
enum EXTENDED_TEXT_MESSAGE_PREVIEWTYPE {
|
||||
NONE = 0;
|
||||
VIDEO = 1;
|
||||
}
|
||||
optional EXTENDED_TEXT_MESSAGE_PREVIEWTYPE previewType = 10;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
@ -90,6 +169,7 @@ message DocumentMessage {
|
|||
optional string fileName = 8;
|
||||
optional bytes fileEncSha256 = 9;
|
||||
optional string directPath = 10;
|
||||
optional int64 mediaKeyTimestamp = 11;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
@ -104,6 +184,7 @@ message AudioMessage {
|
|||
optional bytes mediaKey = 7;
|
||||
optional bytes fileEncSha256 = 8;
|
||||
optional string directPath = 9;
|
||||
optional int64 mediaKeyTimestamp = 10;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
optional bytes streamingSidecar = 18;
|
||||
}
|
||||
|
@ -122,15 +203,16 @@ message VideoMessage {
|
|||
optional bytes fileEncSha256 = 11;
|
||||
repeated InteractiveAnnotation interactiveAnnotations = 12;
|
||||
optional string directPath = 13;
|
||||
optional int64 mediaKeyTimestamp = 14;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
optional bytes streamingSidecar = 18;
|
||||
enum ATTRIBUTION {
|
||||
enum VIDEO_MESSAGE_ATTRIBUTION {
|
||||
NONE = 0;
|
||||
GIPHY = 1;
|
||||
TENOR = 2;
|
||||
}
|
||||
optional ATTRIBUTION gifAttribution = 19;
|
||||
optional VIDEO_MESSAGE_ATTRIBUTION gifAttribution = 19;
|
||||
}
|
||||
|
||||
message Call {
|
||||
|
@ -144,10 +226,10 @@ message Chat {
|
|||
|
||||
message ProtocolMessage {
|
||||
optional MessageKey key = 1;
|
||||
enum TYPE {
|
||||
enum PROTOCOL_MESSAGE_TYPE {
|
||||
REVOKE = 0;
|
||||
}
|
||||
optional TYPE type = 2;
|
||||
optional PROTOCOL_MESSAGE_TYPE type = 2;
|
||||
}
|
||||
|
||||
message ContactsArrayMessage {
|
||||
|
@ -162,7 +244,7 @@ message HSMCurrency {
|
|||
}
|
||||
|
||||
message HSMDateTimeComponent {
|
||||
enum DAYOFWEEKTYPE {
|
||||
enum HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE {
|
||||
MONDAY = 1;
|
||||
TUESDAY = 2;
|
||||
WEDNESDAY = 3;
|
||||
|
@ -171,17 +253,17 @@ message HSMDateTimeComponent {
|
|||
SATURDAY = 6;
|
||||
SUNDAY = 7;
|
||||
}
|
||||
optional DAYOFWEEKTYPE dayOfWeek = 1;
|
||||
optional HSM_DATE_TIME_COMPONENT_DAYOFWEEKTYPE dayOfWeek = 1;
|
||||
optional uint32 year = 2;
|
||||
optional uint32 month = 3;
|
||||
optional uint32 dayOfMonth = 4;
|
||||
optional uint32 hour = 5;
|
||||
optional uint32 minute = 6;
|
||||
enum CALENDARTYPE {
|
||||
enum HSM_DATE_TIME_COMPONENT_CALENDARTYPE {
|
||||
GREGORIAN = 1;
|
||||
SOLAR_HIJRI = 2;
|
||||
}
|
||||
optional CALENDARTYPE calendar = 7;
|
||||
optional HSM_DATE_TIME_COMPONENT_CALENDARTYPE calendar = 7;
|
||||
}
|
||||
|
||||
message HSMDateTimeUnixEpoch {
|
||||
|
@ -210,17 +292,29 @@ message HighlyStructuredMessage {
|
|||
optional string fallbackLg = 4;
|
||||
optional string fallbackLc = 5;
|
||||
repeated HSMLocalizableParameter localizableParams = 6;
|
||||
optional string deterministicLg = 7;
|
||||
optional string deterministicLc = 8;
|
||||
}
|
||||
|
||||
message SendPaymentMessage {
|
||||
optional Message noteMessage = 2;
|
||||
optional MessageKey requestMessageKey = 3;
|
||||
}
|
||||
|
||||
message RequestPaymentMessage {
|
||||
optional Message noteMessage = 4;
|
||||
optional string currencyCodeIso4217 = 1;
|
||||
optional uint64 amount1000 = 2;
|
||||
optional string requestFrom = 3;
|
||||
optional Message noteMessage = 4;
|
||||
optional int64 expiryTimestamp = 5;
|
||||
}
|
||||
|
||||
message DeclinePaymentRequestMessage {
|
||||
optional MessageKey key = 1;
|
||||
}
|
||||
|
||||
message CancelPaymentRequestMessage {
|
||||
optional MessageKey key = 1;
|
||||
}
|
||||
|
||||
message LiveLocationMessage {
|
||||
|
@ -231,6 +325,7 @@ message LiveLocationMessage {
|
|||
optional uint32 degreesClockwiseFromMagneticNorth = 5;
|
||||
optional string caption = 6;
|
||||
optional int64 sequenceNumber = 7;
|
||||
optional uint32 timeOffset = 8;
|
||||
optional bytes jpegThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
@ -245,10 +340,77 @@ message StickerMessage {
|
|||
optional uint32 width = 7;
|
||||
optional string directPath = 8;
|
||||
optional uint64 fileLength = 9;
|
||||
optional int64 mediaKeyTimestamp = 10;
|
||||
optional bytes pngThumbnail = 16;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
||||
message FourRowTemplate {
|
||||
optional HighlyStructuredMessage content = 6;
|
||||
optional HighlyStructuredMessage footer = 7;
|
||||
repeated TemplateButton buttons = 8;
|
||||
oneof title {
|
||||
DocumentMessage documentMessage = 1;
|
||||
HighlyStructuredMessage highlyStructuredMessage = 2;
|
||||
ImageMessage imageMessage = 3;
|
||||
VideoMessage videoMessage = 4;
|
||||
LocationMessage locationMessage = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message HydratedFourRowTemplate {
|
||||
optional string hydratedContentText = 6;
|
||||
optional string hydratedFooterText = 7;
|
||||
repeated HydratedTemplateButton hydratedButtons = 9;
|
||||
oneof title {
|
||||
DocumentMessage documentMessage = 1;
|
||||
string hydratedTitleText = 2;
|
||||
ImageMessage imageMessage = 3;
|
||||
VideoMessage videoMessage = 4;
|
||||
LocationMessage locationMessage = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message TemplateMessage {
|
||||
oneof format {
|
||||
FourRowTemplate fourRowTemplate = 1;
|
||||
HydratedFourRowTemplate hydratedFourRowTemplate = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message TemplateButtonReplyMessage {
|
||||
optional string selectedButtonId = 1;
|
||||
repeated string selectedButtonDisplayText = 2;
|
||||
optional ContextInfo contextInfo = 3;
|
||||
}
|
||||
|
||||
message ProductSnapshot {
|
||||
optional ImageMessage productImage = 1;
|
||||
optional string productId = 2;
|
||||
optional string title = 3;
|
||||
optional string description = 4;
|
||||
optional string currencyCode = 5;
|
||||
optional int64 priceAmount1000 = 6;
|
||||
optional string retailerId = 7;
|
||||
optional string url = 8;
|
||||
optional uint32 productImageCount = 9;
|
||||
}
|
||||
|
||||
message ProductMessage {
|
||||
optional ProductSnapshot product = 1;
|
||||
optional string businessOwnerJid = 2;
|
||||
optional ContextInfo contextInfo = 17;
|
||||
}
|
||||
|
||||
message GroupInviteMessage {
|
||||
optional string groupJid = 1;
|
||||
optional string inviteCode = 2;
|
||||
optional int64 inviteExpiration = 3;
|
||||
optional string groupName = 4;
|
||||
optional bytes jpegThumbnail = 5;
|
||||
optional string caption = 6;
|
||||
}
|
||||
|
||||
message Message {
|
||||
optional string conversation = 1;
|
||||
optional SenderKeyDistributionMessage senderKeyDistributionMessage = 2;
|
||||
|
@ -266,47 +428,104 @@ message Message {
|
|||
optional HighlyStructuredMessage highlyStructuredMessage = 14;
|
||||
optional SenderKeyDistributionMessage fastRatchetKeySenderKeyDistributionMessage = 15;
|
||||
optional SendPaymentMessage sendPaymentMessage = 16;
|
||||
optional RequestPaymentMessage requestPaymentMessage = 17;
|
||||
optional LiveLocationMessage liveLocationMessage = 18;
|
||||
optional StickerMessage stickerMessage = 20;
|
||||
optional RequestPaymentMessage requestPaymentMessage = 22;
|
||||
optional DeclinePaymentRequestMessage declinePaymentRequestMessage = 23;
|
||||
optional CancelPaymentRequestMessage cancelPaymentRequestMessage = 24;
|
||||
optional TemplateMessage templateMessage = 25;
|
||||
optional StickerMessage stickerMessage = 26;
|
||||
optional ProductMessage productMessage = 27;
|
||||
optional GroupInviteMessage groupInviteMessage = 28;
|
||||
}
|
||||
|
||||
message ContextInfo {
|
||||
optional string stanzaId = 1;
|
||||
optional string participant = 2;
|
||||
repeated Message quotedMessage = 3;
|
||||
optional string remoteJid = 4;
|
||||
repeated string mentionedJid = 15;
|
||||
optional string conversionSource = 18;
|
||||
optional bytes conversionData = 19;
|
||||
optional uint32 conversionDelaySeconds = 20;
|
||||
optional bool isForwarded = 22;
|
||||
reserved 16, 17;
|
||||
message MessageKey {
|
||||
optional string remoteJid = 1;
|
||||
optional bool fromMe = 2;
|
||||
optional string id = 3;
|
||||
optional string participant = 4;
|
||||
}
|
||||
|
||||
message InteractiveAnnotation {
|
||||
repeated Point polygonVertices = 1;
|
||||
oneof action {
|
||||
Location location = 2;
|
||||
message WebFeatures {
|
||||
enum WEB_FEATURES_FLAG {
|
||||
NOT_IMPLEMENTED = 0;
|
||||
IMPLEMENTED = 1;
|
||||
OPTIONAL = 2;
|
||||
}
|
||||
optional WEB_FEATURES_FLAG labelsDisplay = 1;
|
||||
optional WEB_FEATURES_FLAG voipIndividualOutgoing = 2;
|
||||
optional WEB_FEATURES_FLAG groupsV3 = 3;
|
||||
optional WEB_FEATURES_FLAG groupsV3Create = 4;
|
||||
optional WEB_FEATURES_FLAG changeNumberV2 = 5;
|
||||
optional WEB_FEATURES_FLAG queryStatusV3Thumbnail = 6;
|
||||
optional WEB_FEATURES_FLAG liveLocations = 7;
|
||||
optional WEB_FEATURES_FLAG queryVname = 8;
|
||||
optional WEB_FEATURES_FLAG voipIndividualIncoming = 9;
|
||||
optional WEB_FEATURES_FLAG quickRepliesQuery = 10;
|
||||
optional WEB_FEATURES_FLAG payments = 11;
|
||||
optional WEB_FEATURES_FLAG stickerPackQuery = 12;
|
||||
optional WEB_FEATURES_FLAG liveLocationsFinal = 13;
|
||||
optional WEB_FEATURES_FLAG labelsEdit = 14;
|
||||
optional WEB_FEATURES_FLAG mediaUpload = 15;
|
||||
optional WEB_FEATURES_FLAG mediaUploadRichQuickReplies = 18;
|
||||
optional WEB_FEATURES_FLAG vnameV2 = 19;
|
||||
optional WEB_FEATURES_FLAG videoPlaybackUrl = 20;
|
||||
optional WEB_FEATURES_FLAG statusRanking = 21;
|
||||
optional WEB_FEATURES_FLAG voipIndividualVideo = 22;
|
||||
optional WEB_FEATURES_FLAG thirdPartyStickers = 23;
|
||||
optional WEB_FEATURES_FLAG frequentlyForwardedSetting = 24;
|
||||
}
|
||||
|
||||
message Point {
|
||||
optional double x = 3;
|
||||
optional double y = 4;
|
||||
message TabletNotificationsInfo {
|
||||
optional uint64 timestamp = 2;
|
||||
optional uint32 unreadChats = 3;
|
||||
optional uint32 notifyMessageCount = 4;
|
||||
repeated NotificationMessageInfo notifyMessage = 5;
|
||||
}
|
||||
|
||||
message Location {
|
||||
optional double degreesLatitude = 1;
|
||||
optional double degreesLongitude = 2;
|
||||
optional string name = 3;
|
||||
message NotificationMessageInfo {
|
||||
optional MessageKey key = 1;
|
||||
optional Message message = 2;
|
||||
optional uint64 messageTimestamp = 3;
|
||||
optional string participant = 4;
|
||||
}
|
||||
|
||||
message WebNotificationsInfo {
|
||||
optional uint64 timestamp = 2;
|
||||
optional uint32 unreadChats = 3;
|
||||
optional uint32 notifyMessageCount = 4;
|
||||
repeated WebMessageInfo notifyMessages = 5;
|
||||
}
|
||||
|
||||
message PaymentInfo {
|
||||
optional uint64 amount1000 = 2;
|
||||
optional string receiverJid = 3;
|
||||
enum PAYMENT_INFO_STATUS {
|
||||
UNKNOWN_STATUS = 0;
|
||||
PROCESSING = 1;
|
||||
SENT = 2;
|
||||
NEED_TO_ACCEPT = 3;
|
||||
COMPLETE = 4;
|
||||
COULD_NOT_COMPLETE = 5;
|
||||
REFUNDED = 6;
|
||||
EXPIRED = 7;
|
||||
REJECTED = 8;
|
||||
CANCELLED = 9;
|
||||
WAITING_FOR_PAYER = 10;
|
||||
WAITING = 11;
|
||||
}
|
||||
optional PAYMENT_INFO_STATUS status = 4;
|
||||
optional uint64 transactionTimestamp = 5;
|
||||
optional MessageKey requestMessageKey = 6;
|
||||
optional uint64 expiryTimestamp = 7;
|
||||
optional bool futureproofed = 8;
|
||||
optional string currency = 9;
|
||||
}
|
||||
|
||||
message WebMessageInfo {
|
||||
required MessageKey key = 1;
|
||||
optional Message message = 2;
|
||||
optional uint64 messageTimestamp = 3;
|
||||
enum STATUS {
|
||||
enum WEB_MESSAGE_INFO_STATUS {
|
||||
ERROR = 0;
|
||||
PENDING = 1;
|
||||
SERVER_ACK = 2;
|
||||
|
@ -314,7 +533,7 @@ message WebMessageInfo {
|
|||
READ = 4;
|
||||
PLAYED = 5;
|
||||
}
|
||||
optional STATUS status = 4 [default=PENDING];
|
||||
optional WEB_MESSAGE_INFO_STATUS status = 4;
|
||||
optional string participant = 5;
|
||||
optional bool ignore = 16;
|
||||
optional bool starred = 17;
|
||||
|
@ -324,7 +543,7 @@ message WebMessageInfo {
|
|||
optional bool multicast = 21;
|
||||
optional bool urlText = 22;
|
||||
optional bool urlNumber = 23;
|
||||
enum STUBTYPE {
|
||||
enum WEB_MESSAGE_INFO_STUBTYPE {
|
||||
UNKNOWN = 0;
|
||||
REVOKE = 1;
|
||||
CIPHERTEXT = 2;
|
||||
|
@ -369,49 +588,39 @@ message WebMessageInfo {
|
|||
CALL_MISSED_VIDEO = 41;
|
||||
INDIVIDUAL_CHANGE_NUMBER = 42;
|
||||
GROUP_DELETE = 43;
|
||||
GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE = 44;
|
||||
CALL_MISSED_GROUP_VOICE = 45;
|
||||
CALL_MISSED_GROUP_VIDEO = 46;
|
||||
PAYMENT_CIPHERTEXT = 47;
|
||||
PAYMENT_FUTUREPROOF = 48;
|
||||
PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED = 49;
|
||||
PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED = 50;
|
||||
PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED = 51;
|
||||
PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP = 52;
|
||||
PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP = 53;
|
||||
PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER = 54;
|
||||
PAYMENT_ACTION_SEND_PAYMENT_REMINDER = 55;
|
||||
PAYMENT_ACTION_SEND_PAYMENT_INVITATION = 56;
|
||||
PAYMENT_ACTION_REQUEST_DECLINED = 57;
|
||||
PAYMENT_ACTION_REQUEST_EXPIRED = 58;
|
||||
PAYMENT_ACTION_REQUEST_CANCELLED = 59;
|
||||
BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM = 60;
|
||||
BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP = 61;
|
||||
BIZ_INTRO_TOP = 62;
|
||||
BIZ_INTRO_BOTTOM = 63;
|
||||
BIZ_NAME_CHANGE = 64;
|
||||
BIZ_MOVE_TO_CONSUMER_APP = 65;
|
||||
BIZ_TWO_TIER_MIGRATION_TOP = 66;
|
||||
BIZ_TWO_TIER_MIGRATION_BOTTOM = 67;
|
||||
OVERSIZED = 68;
|
||||
GROUP_CHANGE_NO_FREQUENTLY_FORWARDED = 69;
|
||||
}
|
||||
optional STUBTYPE messageStubType = 24;
|
||||
optional WEB_MESSAGE_INFO_STUBTYPE messageStubType = 24;
|
||||
optional bool clearMedia = 25;
|
||||
repeated string messageStubParameters = 26;
|
||||
optional uint32 duration = 27;
|
||||
repeated string labels = 28;
|
||||
}
|
||||
|
||||
message WebNotificationsInfo {
|
||||
optional uint64 timestamp = 2;
|
||||
optional uint32 unreadChats = 3;
|
||||
optional uint32 notifyMessageCount = 4;
|
||||
repeated Message notifyMessages = 5;
|
||||
}
|
||||
|
||||
message NotificationMessageInfo {
|
||||
optional MessageKey key = 1;
|
||||
optional Message message = 2;
|
||||
optional uint64 messageTimestamp = 3;
|
||||
optional string participant = 4;
|
||||
}
|
||||
|
||||
message TabletNotificationsInfo {
|
||||
optional uint64 timestamp = 2;
|
||||
optional uint32 unreadChats = 3;
|
||||
optional uint32 notifyMessageCount = 4;
|
||||
repeated Message notifyMessage = 5;
|
||||
}
|
||||
|
||||
message WebFeatures {
|
||||
enum FLAG {
|
||||
NOT_IMPLEMENTED = 0;
|
||||
IMPLEMENTED = 1;
|
||||
OPTIONAL = 2;
|
||||
}
|
||||
optional FLAG labelsDisplay = 1;
|
||||
optional FLAG voipIndividualOutgoing = 2;
|
||||
optional FLAG groupsV3 = 3;
|
||||
optional FLAG groupsV3Create = 4;
|
||||
optional FLAG changeNumberV2 = 5;
|
||||
optional FLAG queryStatusV3Thumbnail = 6;
|
||||
optional FLAG liveLocations = 7;
|
||||
optional FLAG queryVname = 8;
|
||||
optional FLAG voipIndividualIncoming = 9;
|
||||
optional FLAG quickRepliesQuery = 10;
|
||||
optional PaymentInfo paymentInfo = 29;
|
||||
optional LiveLocationMessage finalLiveLocation = 30;
|
||||
optional PaymentInfo quotedPaymentInfo = 31;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package whatsapp
|
|||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -91,6 +92,7 @@ type Conn struct {
|
|||
shortClientName string
|
||||
|
||||
loginSessionLock sync.RWMutex
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
type websocketWrapper struct {
|
||||
|
@ -121,6 +123,21 @@ func NewConn(timeout time.Duration) (*Conn, error) {
|
|||
return wac, wac.connect()
|
||||
}
|
||||
|
||||
// NewConnWithProxy Create a new connect with a given timeout and a http proxy.
|
||||
func NewConnWithProxy(timeout time.Duration, proxy func(*http.Request) (*url.URL, error)) (*Conn, error) {
|
||||
wac := &Conn{
|
||||
handler: make([]Handler, 0),
|
||||
msgCount: 0,
|
||||
msgTimeout: timeout,
|
||||
Store: newStore(),
|
||||
|
||||
longClientName: "github.com/rhymen/go-whatsapp",
|
||||
shortClientName: "go-whatsapp",
|
||||
Proxy: proxy,
|
||||
}
|
||||
return wac, wac.connect()
|
||||
}
|
||||
|
||||
// connect should be guarded with wsWriteMutex
|
||||
func (wac *Conn) connect() (err error) {
|
||||
if wac.connected {
|
||||
|
@ -137,6 +154,7 @@ func (wac *Conn) connect() (err error) {
|
|||
ReadBufferSize: 25 * 1024 * 1024,
|
||||
WriteBufferSize: 10 * 1024 * 1024,
|
||||
HandshakeTimeout: wac.msgTimeout,
|
||||
Proxy: wac.Proxy,
|
||||
}
|
||||
|
||||
headers := http.Header{"Origin": []string{"https://web.whatsapp.com"}}
|
||||
|
@ -202,7 +220,7 @@ func (wac *Conn) AdminTest() (bool, error) {
|
|||
return false, ErrInvalidSession
|
||||
}
|
||||
|
||||
result, err := wac.sendAdminTest()
|
||||
result, err := wac.sendAdminTest()
|
||||
return result, err
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ func (wac *Conn) LoadMessagesAfter(jid, messageId string, count int) (*binary.No
|
|||
return wac.query("message", jid, messageId, "after", "true", "", count, 0)
|
||||
}
|
||||
|
||||
func (wac *Conn) LoadMediaInfo(jid, messageId, owner string) (*binary.Node, error) {
|
||||
return wac.query("media", jid, messageId, "", owner, "", 0, 0)
|
||||
}
|
||||
|
||||
func (wac *Conn) Presence(jid string, presence Presence) (<-chan string, error) {
|
||||
ts := time.Now().Unix()
|
||||
tag := fmt.Sprintf("%d.--%d", ts, wac.msgCount)
|
||||
|
@ -163,7 +167,12 @@ func (wac *Conn) query(t, jid, messageId, kind, owner, search string, count, pag
|
|||
n.Attributes["page"] = strconv.Itoa(page)
|
||||
}
|
||||
|
||||
ch, err := wac.writeBinary(n, group, ignore, tag)
|
||||
metric := group
|
||||
if t == "media" {
|
||||
metric = queryMedia
|
||||
}
|
||||
|
||||
ch, err := wac.writeBinary(n, metric, ignore, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -6,18 +6,20 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrAlreadyConnected = errors.New("already connected")
|
||||
ErrAlreadyLoggedIn = errors.New("already logged in")
|
||||
ErrInvalidSession = errors.New("invalid session")
|
||||
ErrLoginInProgress = errors.New("login or restore already running")
|
||||
ErrNotConnected = errors.New("not connected")
|
||||
ErrInvalidWsData = errors.New("received invalid data")
|
||||
ErrInvalidWsState = errors.New("can't handle binary data when not logged in")
|
||||
ErrConnectionTimeout = errors.New("connection timed out")
|
||||
ErrMissingMessageTag = errors.New("no messageTag specified or to short")
|
||||
ErrInvalidHmac = errors.New("invalid hmac")
|
||||
ErrInvalidServerResponse = errors.New("invalid response received from server")
|
||||
ErrServerRespondedWith404 = errors.New("server responded with status 404")
|
||||
ErrAlreadyConnected = errors.New("already connected")
|
||||
ErrAlreadyLoggedIn = errors.New("already logged in")
|
||||
ErrInvalidSession = errors.New("invalid session")
|
||||
ErrLoginInProgress = errors.New("login or restore already running")
|
||||
ErrNotConnected = errors.New("not connected")
|
||||
ErrInvalidWsData = errors.New("received invalid data")
|
||||
ErrInvalidWsState = errors.New("can't handle binary data when not logged in")
|
||||
ErrConnectionTimeout = errors.New("connection timed out")
|
||||
ErrMissingMessageTag = errors.New("no messageTag specified or to short")
|
||||
ErrInvalidHmac = errors.New("invalid hmac")
|
||||
ErrInvalidServerResponse = errors.New("invalid response received from server")
|
||||
ErrServerRespondedWith404 = errors.New("server responded with status 404")
|
||||
ErrMediaDownloadFailedWith404 = errors.New("download failed with status code 404")
|
||||
ErrMediaDownloadFailedWith410 = errors.New("download failed with status code 410")
|
||||
)
|
||||
|
||||
type ErrConnectionFailed struct {
|
||||
|
|
|
@ -81,6 +81,14 @@ type LocationMessageHandler interface {
|
|||
HandleLocationMessage(message LocationMessage)
|
||||
}
|
||||
|
||||
/*
|
||||
The StickerMessageHandler interface needs to be implemented to receive location messages dispatched by the dispatcher.
|
||||
*/
|
||||
type StickerMessageHandler interface {
|
||||
Handler
|
||||
HandleStickerMessage(message StickerMessage)
|
||||
}
|
||||
|
||||
/*
|
||||
The JsonMessageHandler interface needs to be implemented to receive json messages dispatched by the dispatcher.
|
||||
These json messages contain status updates of every kind sent by WhatsAppWeb servers. WhatsAppWeb uses these messages
|
||||
|
@ -247,6 +255,18 @@ func (wac *Conn) handleWithCustomHandlers(message interface{}, handlers []Handle
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
case StickerMessage:
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(StickerMessageHandler); ok {
|
||||
if wac.shouldCallSynchronously(h) {
|
||||
x.HandleStickerMessage(m)
|
||||
} else {
|
||||
go x.HandleStickerMessage(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case *proto.WebMessageInfo:
|
||||
for _, h := range handlers {
|
||||
if x, ok := h.(RawMessageHandler); ok {
|
||||
|
|
|
@ -74,6 +74,12 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode == 404 {
|
||||
return nil, nil, ErrMediaDownloadFailedWith404
|
||||
}
|
||||
if resp.StatusCode == 410 {
|
||||
return nil, nil, ErrMediaDownloadFailedWith410
|
||||
}
|
||||
return nil, nil, fmt.Errorf("download failed with status code %d", resp.StatusCode)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
|
|
@ -4,13 +4,14 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/binary/proto"
|
||||
)
|
||||
|
||||
type MediaType string
|
||||
|
@ -131,6 +132,7 @@ type MessageInfo struct {
|
|||
PushName string
|
||||
Status MessageStatus
|
||||
QuotedMessageID string
|
||||
QuotedMessage proto.Message
|
||||
|
||||
Source *proto.WebMessageInfo
|
||||
}
|
||||
|
@ -170,7 +172,7 @@ func getInfoProto(info *MessageInfo) *proto.WebMessageInfo {
|
|||
}
|
||||
info.FromMe = true
|
||||
|
||||
status := proto.WebMessageInfo_STATUS(info.Status)
|
||||
status := proto.WebMessageInfo_WEB_MESSAGE_INFO_STATUS(info.Status)
|
||||
|
||||
return &proto.WebMessageInfo{
|
||||
Key: &proto.MessageKey{
|
||||
|
@ -183,6 +185,22 @@ func getInfoProto(info *MessageInfo) *proto.WebMessageInfo {
|
|||
}
|
||||
}
|
||||
|
||||
func getContextInfoProto(info *MessageInfo) *proto.ContextInfo {
|
||||
if len(info.QuotedMessageID) > 0 {
|
||||
contextInfo := &proto.ContextInfo{
|
||||
StanzaId: &info.QuotedMessageID,
|
||||
}
|
||||
|
||||
if &info.QuotedMessage != nil {
|
||||
contextInfo.QuotedMessage = &info.QuotedMessage
|
||||
}
|
||||
|
||||
return contextInfo
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
TextMessage represents a text message.
|
||||
*/
|
||||
|
@ -204,9 +222,21 @@ func getTextMessage(msg *proto.WebMessageInfo) TextMessage {
|
|||
|
||||
func getTextProto(msg TextMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
Conversation: &msg.Text,
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
|
||||
if contextInfo == nil {
|
||||
p.Message = &proto.Message{
|
||||
Conversation: &msg.Text,
|
||||
}
|
||||
} else {
|
||||
p.Message = &proto.Message{
|
||||
ExtendedTextMessage: &proto.ExtendedTextMessage{
|
||||
Text: &msg.Text,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -229,7 +259,8 @@ type ImageMessage struct {
|
|||
|
||||
func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
|
||||
image := msg.GetMessage().GetImageMessage()
|
||||
return ImageMessage{
|
||||
|
||||
imageMessage := ImageMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
Caption: image.GetCaption(),
|
||||
Thumbnail: image.GetJpegThumbnail(),
|
||||
|
@ -240,10 +271,18 @@ func getImageMessage(msg *proto.WebMessageInfo) ImageMessage {
|
|||
fileSha256: image.GetFileSha256(),
|
||||
fileLength: image.GetFileLength(),
|
||||
}
|
||||
|
||||
if contextInfo := image.GetContextInfo(); contextInfo != nil {
|
||||
imageMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return imageMessage
|
||||
}
|
||||
|
||||
func getImageProto(msg ImageMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
|
||||
p.Message = &proto.Message{
|
||||
ImageMessage: &proto.ImageMessage{
|
||||
Caption: &msg.Caption,
|
||||
|
@ -254,6 +293,7 @@ func getImageProto(msg ImageMessage) *proto.WebMessageInfo {
|
|||
FileEncSha256: msg.fileEncSha256,
|
||||
FileSha256: msg.fileSha256,
|
||||
FileLength: &msg.fileLength,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
return p
|
||||
|
@ -287,7 +327,8 @@ type VideoMessage struct {
|
|||
|
||||
func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
|
||||
vid := msg.GetMessage().GetVideoMessage()
|
||||
return VideoMessage{
|
||||
|
||||
videoMessage := VideoMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
Caption: vid.GetCaption(),
|
||||
Thumbnail: vid.GetJpegThumbnail(),
|
||||
|
@ -300,10 +341,18 @@ func getVideoMessage(msg *proto.WebMessageInfo) VideoMessage {
|
|||
fileSha256: vid.GetFileSha256(),
|
||||
fileLength: vid.GetFileLength(),
|
||||
}
|
||||
|
||||
if contextInfo := vid.GetContextInfo(); contextInfo != nil {
|
||||
videoMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return videoMessage
|
||||
}
|
||||
|
||||
func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
|
||||
p.Message = &proto.Message{
|
||||
VideoMessage: &proto.VideoMessage{
|
||||
Caption: &msg.Caption,
|
||||
|
@ -316,6 +365,7 @@ func getVideoProto(msg VideoMessage) *proto.WebMessageInfo {
|
|||
FileSha256: msg.fileSha256,
|
||||
FileLength: &msg.fileLength,
|
||||
Mimetype: &msg.Type,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
return p
|
||||
|
@ -337,6 +387,7 @@ type AudioMessage struct {
|
|||
Length uint32
|
||||
Type string
|
||||
Content io.Reader
|
||||
Ptt bool
|
||||
url string
|
||||
mediaKey []byte
|
||||
fileEncSha256 []byte
|
||||
|
@ -346,7 +397,8 @@ type AudioMessage struct {
|
|||
|
||||
func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
|
||||
aud := msg.GetMessage().GetAudioMessage()
|
||||
return AudioMessage{
|
||||
|
||||
audioMessage := AudioMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
url: aud.GetUrl(),
|
||||
mediaKey: aud.GetMediaKey(),
|
||||
|
@ -356,10 +408,17 @@ func getAudioMessage(msg *proto.WebMessageInfo) AudioMessage {
|
|||
fileSha256: aud.GetFileSha256(),
|
||||
fileLength: aud.GetFileLength(),
|
||||
}
|
||||
|
||||
if contextInfo := aud.GetContextInfo(); contextInfo != nil {
|
||||
audioMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return audioMessage
|
||||
}
|
||||
|
||||
func getAudioProto(msg AudioMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
AudioMessage: &proto.AudioMessage{
|
||||
Url: &msg.url,
|
||||
|
@ -369,6 +428,8 @@ func getAudioProto(msg AudioMessage) *proto.WebMessageInfo {
|
|||
FileSha256: msg.fileSha256,
|
||||
FileLength: &msg.fileLength,
|
||||
Mimetype: &msg.Type,
|
||||
ContextInfo: contextInfo,
|
||||
Ptt: &msg.Ptt,
|
||||
},
|
||||
}
|
||||
return p
|
||||
|
@ -402,7 +463,8 @@ type DocumentMessage struct {
|
|||
|
||||
func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
|
||||
doc := msg.GetMessage().GetDocumentMessage()
|
||||
return DocumentMessage{
|
||||
|
||||
documentMessage := DocumentMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
Title: doc.GetTitle(),
|
||||
PageCount: doc.GetPageCount(),
|
||||
|
@ -415,10 +477,17 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
|
|||
fileSha256: doc.GetFileSha256(),
|
||||
fileLength: doc.GetFileLength(),
|
||||
}
|
||||
|
||||
if contextInfo := doc.GetContextInfo(); contextInfo != nil {
|
||||
documentMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return documentMessage
|
||||
}
|
||||
|
||||
func getDocumentProto(msg DocumentMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
DocumentMessage: &proto.DocumentMessage{
|
||||
JpegThumbnail: msg.Thumbnail,
|
||||
|
@ -430,6 +499,7 @@ func getDocumentProto(msg DocumentMessage) *proto.WebMessageInfo {
|
|||
PageCount: &msg.PageCount,
|
||||
Title: &msg.Title,
|
||||
Mimetype: &msg.Type,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
return p
|
||||
|
@ -457,7 +527,8 @@ type LocationMessage struct {
|
|||
|
||||
func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
|
||||
loc := msg.GetMessage().GetLocationMessage()
|
||||
return LocationMessage{
|
||||
|
||||
locationMessage := LocationMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
DegreesLatitude: loc.GetDegreesLatitude(),
|
||||
DegreesLongitude: loc.GetDegreesLongitude(),
|
||||
|
@ -466,10 +537,18 @@ func GetLocationMessage(msg *proto.WebMessageInfo) LocationMessage {
|
|||
Url: loc.GetUrl(),
|
||||
JpegThumbnail: loc.GetJpegThumbnail(),
|
||||
}
|
||||
|
||||
if contextInfo := loc.GetContextInfo(); contextInfo != nil {
|
||||
locationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return locationMessage
|
||||
}
|
||||
|
||||
func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
|
||||
p.Message = &proto.Message{
|
||||
LocationMessage: &proto.LocationMessage{
|
||||
DegreesLatitude: &msg.DegreesLatitude,
|
||||
|
@ -478,6 +557,7 @@ func GetLocationProto(msg LocationMessage) *proto.WebMessageInfo {
|
|||
Address: &msg.Address,
|
||||
Url: &msg.Url,
|
||||
JpegThumbnail: msg.JpegThumbnail,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
return p
|
||||
|
@ -500,7 +580,8 @@ type LiveLocationMessage struct {
|
|||
|
||||
func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
|
||||
loc := msg.GetMessage().GetLiveLocationMessage()
|
||||
return LiveLocationMessage{
|
||||
|
||||
liveLocationMessage := LiveLocationMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
DegreesLatitude: loc.GetDegreesLatitude(),
|
||||
DegreesLongitude: loc.GetDegreesLongitude(),
|
||||
|
@ -511,10 +592,17 @@ func GetLiveLocationMessage(msg *proto.WebMessageInfo) LiveLocationMessage {
|
|||
SequenceNumber: loc.GetSequenceNumber(),
|
||||
JpegThumbnail: loc.GetJpegThumbnail(),
|
||||
}
|
||||
|
||||
if contextInfo := loc.GetContextInfo(); contextInfo != nil {
|
||||
liveLocationMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return liveLocationMessage
|
||||
}
|
||||
|
||||
func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
|
||||
p := getInfoProto(&msg.Info)
|
||||
contextInfo := getContextInfoProto(&msg.Info)
|
||||
p.Message = &proto.Message{
|
||||
LiveLocationMessage: &proto.LiveLocationMessage{
|
||||
DegreesLatitude: &msg.DegreesLatitude,
|
||||
|
@ -525,11 +613,49 @@ func GetLiveLocationProto(msg LiveLocationMessage) *proto.WebMessageInfo {
|
|||
Caption: &msg.Caption,
|
||||
SequenceNumber: &msg.SequenceNumber,
|
||||
JpegThumbnail: msg.JpegThumbnail,
|
||||
ContextInfo: contextInfo,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
/*
|
||||
StickerMessage represents a sticker message.
|
||||
*/
|
||||
type StickerMessage struct {
|
||||
Info MessageInfo
|
||||
|
||||
Thumbnail []byte
|
||||
Type string
|
||||
Content io.Reader
|
||||
url string
|
||||
mediaKey []byte
|
||||
fileEncSha256 []byte
|
||||
fileSha256 []byte
|
||||
fileLength uint64
|
||||
}
|
||||
|
||||
func getStickerMessage(msg *proto.WebMessageInfo) StickerMessage {
|
||||
sticker := msg.GetMessage().GetStickerMessage()
|
||||
|
||||
StickerMessage := StickerMessage{
|
||||
Info: getMessageInfo(msg),
|
||||
Thumbnail: sticker.GetPngThumbnail(),
|
||||
url: sticker.GetUrl(),
|
||||
mediaKey: sticker.GetMediaKey(),
|
||||
Type: sticker.GetMimetype(),
|
||||
fileEncSha256: sticker.GetFileEncSha256(),
|
||||
fileSha256: sticker.GetFileSha256(),
|
||||
fileLength: sticker.GetFileLength(),
|
||||
}
|
||||
|
||||
if contextInfo := sticker.GetContextInfo(); contextInfo != nil {
|
||||
StickerMessage.Info.QuotedMessageID = contextInfo.GetStanzaId()
|
||||
}
|
||||
|
||||
return StickerMessage
|
||||
}
|
||||
|
||||
func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
|
||||
switch {
|
||||
|
||||
|
@ -557,6 +683,9 @@ func ParseProtoMessage(msg *proto.WebMessageInfo) interface{} {
|
|||
case msg.GetMessage().GetLiveLocationMessage() != nil:
|
||||
return GetLiveLocationMessage(msg)
|
||||
|
||||
case msg.GetMessage().GetStickerMessage() != nil:
|
||||
return getStickerMessage(msg)
|
||||
|
||||
default:
|
||||
//cannot match message
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
@ -88,6 +90,53 @@ func newInfoFromReq(info map[string]interface{}) *Info {
|
|||
return ret
|
||||
}
|
||||
|
||||
/*
|
||||
CheckCurrentServerVersion is based on the login method logic in order to establish the websocket connection and get
|
||||
the current version from the server with the `admin init` command. This can be very useful for automations in which
|
||||
you need to quickly perceive new versions (mostly patches) and update your application so it suddenly stops working.
|
||||
*/
|
||||
func CheckCurrentServerVersion() ([]int, error) {
|
||||
wac, err := NewConn(5 * time.Second)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to create connection")
|
||||
}
|
||||
|
||||
clientId := make([]byte, 16)
|
||||
if _, err = rand.Read(clientId); err != nil {
|
||||
return nil, fmt.Errorf("error creating random ClientId: %v", err)
|
||||
}
|
||||
|
||||
b64ClientId := base64.StdEncoding.EncodeToString(clientId)
|
||||
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, b64ClientId, true}
|
||||
loginChan, err := wac.writeJson(login)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing login", err)
|
||||
}
|
||||
|
||||
// Retrieve an answer from the websocket
|
||||
var r string
|
||||
select {
|
||||
case r = <-loginChan:
|
||||
case <-time.After(wac.msgTimeout):
|
||||
return nil, fmt.Errorf("login connection timed out")
|
||||
}
|
||||
|
||||
var resp map[string]interface{}
|
||||
if err = json.Unmarshal([]byte(r), &resp); err != nil {
|
||||
return nil, fmt.Errorf("error decoding login", err)
|
||||
}
|
||||
|
||||
// Take the curr property as X.Y.Z and split it into as int slice
|
||||
curr := resp["curr"].(string)
|
||||
currArray := strings.Split(curr, ".")
|
||||
version := make([]int, len(currArray))
|
||||
for i := range version {
|
||||
version[i], _ = strconv.Atoi(currArray[i])
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
/*
|
||||
SetClientName sets the long and short client names that are sent to WhatsApp when logging in and displayed in the
|
||||
WhatsApp Web device list. As the values are only sent when logging in, changing them after logging in is not possible.
|
||||
|
@ -108,6 +157,11 @@ func (wac *Conn) SetClientVersion(major int, minor int, patch int) {
|
|||
waVersion = []int{major, minor, patch}
|
||||
}
|
||||
|
||||
// GetClientVersion returns WhatsApp client version
|
||||
func (wac *Conn) GetClientVersion() []int {
|
||||
return waVersion
|
||||
}
|
||||
|
||||
/*
|
||||
Login is the function that creates a new whatsapp session and logs you in. If you do not want to scan the qr code
|
||||
every time, you should save the returned session and use RestoreWithSession the next time. Login takes a writable channel
|
||||
|
|
|
@ -78,13 +78,13 @@ func (wac *Conn) sendKeepAlive() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
When phone is unreachable, WhatsAppWeb sends ["admin","test"] time after time to try a successful contact.
|
||||
Tested with Airplane mode and no connection at all.
|
||||
*/
|
||||
func (wac *Conn) sendAdminTest() (bool, error) {
|
||||
data := []interface{}{"admin", "test"}
|
||||
|
||||
|
||||
r, err := wac.writeJson(data)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error sending admin test")
|
||||
|
@ -103,9 +103,9 @@ func (wac *Conn) sendAdminTest() (bool, error) {
|
|||
|
||||
if len(response) == 2 && response[0].(string) == "Pong" && response[1].(bool) == true {
|
||||
return true, nil
|
||||
} else{
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wac *Conn) write(messageType int, answerMessageTag string, data []byte) (<-chan string, error) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# DiscordGo
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.gg/0SBTUU1wZTWT6sqd)
|
||||
[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discordapp.com/invite/discord-api)
|
||||
|
||||
<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
||||
const VERSION = "0.19.0"
|
||||
const VERSION = "0.20.1"
|
||||
|
||||
// ErrMFA will be risen by New when the user has 2FA.
|
||||
var ErrMFA = errors.New("account has 2FA enabled")
|
||||
|
@ -58,6 +58,7 @@ func New(args ...interface{}) (s *Session, err error) {
|
|||
ShardCount: 1,
|
||||
MaxRestRetries: 3,
|
||||
Client: &http.Client{Timeout: (20 * time.Second)},
|
||||
UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
|
||||
sequence: new(int64),
|
||||
LastHeartbeatAck: time.Now().UTC(),
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ var (
|
|||
EndpointCDNIcons = EndpointCDN + "icons/"
|
||||
EndpointCDNSplashes = EndpointCDN + "splashes/"
|
||||
EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
|
||||
EndpointCDNBanners = EndpointCDN + "banners/"
|
||||
|
||||
EndpointAuth = EndpointAPI + "auth/"
|
||||
EndpointLogin = EndpointAuth + "login"
|
||||
|
@ -92,11 +93,13 @@ var (
|
|||
EndpointGuildEmbed = func(gID string) string { return EndpointGuilds + gID + "/embed" }
|
||||
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
|
||||
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
|
||||
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
|
||||
EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
|
||||
EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
|
||||
EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
|
||||
EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
|
||||
EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
|
||||
EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
|
||||
|
||||
EndpointChannel = func(cID string) string { return EndpointChannels + cID }
|
||||
EndpointChannelPermissions = func(cID string) string { return EndpointChannels + cID + "/permissions" }
|
||||
|
@ -139,8 +142,9 @@ var (
|
|||
EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" }
|
||||
EndpointEmojiAnimated = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".gif" }
|
||||
|
||||
EndpointOauth2 = EndpointAPI + "oauth2/"
|
||||
EndpointApplications = EndpointOauth2 + "applications"
|
||||
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
|
||||
EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" }
|
||||
EndpointOauth2 = EndpointAPI + "oauth2/"
|
||||
EndpointApplications = EndpointOauth2 + "applications"
|
||||
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
|
||||
EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" }
|
||||
EndpointApplicationAssets = func(aID string) string { return EndpointApplications + "/" + aID + "/assets" }
|
||||
)
|
||||
|
|
|
@ -10,15 +10,15 @@ import (
|
|||
//go:generate go run tools/cmd/eventhandlers/main.go
|
||||
|
||||
// Connect is the data for a Connect event.
|
||||
// This is a sythetic event and is not dispatched by Discord.
|
||||
// This is a synthetic event and is not dispatched by Discord.
|
||||
type Connect struct{}
|
||||
|
||||
// Disconnect is the data for a Disconnect event.
|
||||
// This is a sythetic event and is not dispatched by Discord.
|
||||
// This is a synthetic event and is not dispatched by Discord.
|
||||
type Disconnect struct{}
|
||||
|
||||
// RateLimit is the data for a RateLimit event.
|
||||
// This is a sythetic event and is not dispatched by Discord.
|
||||
// This is a synthetic event and is not dispatched by Discord.
|
||||
type RateLimit struct {
|
||||
*TooManyRequests
|
||||
URL string
|
||||
|
@ -162,6 +162,8 @@ type MessageCreate struct {
|
|||
// MessageUpdate is the data for a MessageUpdate event.
|
||||
type MessageUpdate struct {
|
||||
*Message
|
||||
// BeforeUpdate will be nil if the Message was not previously cached in the state cache.
|
||||
BeforeUpdate *Message `json:"-"`
|
||||
}
|
||||
|
||||
// MessageDelete is the data for a MessageDelete event.
|
||||
|
|
|
@ -28,6 +28,11 @@ const (
|
|||
MessageTypeChannelIconChange
|
||||
MessageTypeChannelPinnedMessage
|
||||
MessageTypeGuildMemberJoin
|
||||
MessageTypeUserPremiumGuildSubscription
|
||||
MessageTypeUserPremiumGuildSubscriptionTierOne
|
||||
MessageTypeUserPremiumGuildSubscriptionTierTwo
|
||||
MessageTypeUserPremiumGuildSubscriptionTierThree
|
||||
MessageTypeChannelFollowAdd
|
||||
)
|
||||
|
||||
// A Message stores all data related to a specific Discord message.
|
||||
|
@ -80,11 +85,39 @@ type Message struct {
|
|||
// A list of reactions to the message.
|
||||
Reactions []*MessageReactions `json:"reactions"`
|
||||
|
||||
// Whether the message is pinned or not.
|
||||
Pinned bool `json:"pinned"`
|
||||
|
||||
// The type of the message.
|
||||
Type MessageType `json:"type"`
|
||||
|
||||
// The webhook ID of the message, if it was generated by a webhook
|
||||
WebhookID string `json:"webhook_id"`
|
||||
|
||||
// Member properties for this message's author,
|
||||
// contains only partial information
|
||||
Member *Member `json:"member"`
|
||||
|
||||
// Channels specifically mentioned in this message
|
||||
// Not all channel mentions in a message will appear in mention_channels.
|
||||
// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
|
||||
// Only crossposted messages (via Channel Following) currently include mention_channels at all.
|
||||
// If no mentions in the message meet these requirements, this field will not be sent.
|
||||
MentionChannels []*Channel `json:"mention_channels"`
|
||||
|
||||
// Is sent with Rich Presence-related chat embeds
|
||||
Activity *MessageActivity `json:"activity"`
|
||||
|
||||
// Is sent with Rich Presence-related chat embeds
|
||||
Application *MessageApplication `json:"application"`
|
||||
|
||||
// MessageReference contains reference data sent with crossposted messages
|
||||
MessageReference *MessageReference `json:"message_reference"`
|
||||
|
||||
// The flags of the message, which describe extra features of a message.
|
||||
// This is a combination of bit masks; the presence of a certain permission can
|
||||
// be checked by performing a bitwise AND between this int and the flag.
|
||||
Flags int `json:"flags"`
|
||||
}
|
||||
|
||||
// File stores info about files you e.g. send in messages.
|
||||
|
@ -225,6 +258,52 @@ type MessageReactions struct {
|
|||
Emoji *Emoji `json:"emoji"`
|
||||
}
|
||||
|
||||
// MessageActivity is sent with Rich Presence-related chat embeds
|
||||
type MessageActivity struct {
|
||||
Type MessageActivityType `json:"type"`
|
||||
PartyID string `json:"party_id"`
|
||||
}
|
||||
|
||||
// MessageActivityType is the type of message activity
|
||||
type MessageActivityType int
|
||||
|
||||
// Constants for the different types of Message Activity
|
||||
const (
|
||||
MessageActivityTypeJoin = iota + 1
|
||||
MessageActivityTypeSpectate
|
||||
MessageActivityTypeListen
|
||||
MessageActivityTypeJoinRequest
|
||||
)
|
||||
|
||||
// MessageFlag describes an extra feature of the message
|
||||
type MessageFlag int
|
||||
|
||||
// Constants for the different bit offsets of Message Flags
|
||||
const (
|
||||
// This message has been published to subscribed channels (via Channel Following)
|
||||
MessageFlagCrossposted = 1 << iota
|
||||
// This message originated from a message in another channel (via Channel Following)
|
||||
MessageFlagIsCrosspost
|
||||
// Do not include any embeds when serializing this message
|
||||
MessageFlagSuppressEmbeds
|
||||
)
|
||||
|
||||
// MessageApplication is sent with Rich Presence-related chat embeds
|
||||
type MessageApplication struct {
|
||||
ID string `json:"id"`
|
||||
CoverImage string `json:"cover_image"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// MessageReference contains reference data sent with crossposted messages
|
||||
type MessageReference struct {
|
||||
MessageID string `json:"message_id"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
GuildID string `json:"guild_id"`
|
||||
}
|
||||
|
||||
// ContentWithMentionsReplaced will replace all @<id> mentions with the
|
||||
// username of the mention.
|
||||
func (m *Message) ContentWithMentionsReplaced() (content string) {
|
||||
|
|
|
@ -105,6 +105,25 @@ func (s *Session) ApplicationDelete(appID string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Asset struct stores values for an asset of an application
|
||||
type Asset struct {
|
||||
Type int `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// ApplicationAssets returns an application's assets
|
||||
func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
|
||||
|
||||
body, err := s.RequestWithBucketID("GET", EndpointApplicationAssets(appID), nil, EndpointApplicationAssets(""))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &ass)
|
||||
return
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Code specific to Discord OAuth2 Application Bots
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -90,7 +90,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
|
|||
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
// TODO: Make a configurable static variable.
|
||||
req.Header.Set("User-Agent", "DiscordBot (https://github.com/bwmarrin/discordgo, v"+VERSION+")")
|
||||
req.Header.Set("User-Agent", s.UserAgent)
|
||||
|
||||
if s.Debug {
|
||||
for k, v := range req.Header {
|
||||
|
@ -617,10 +617,10 @@ func (s *Session) GuildCreate(name string) (st *Guild, err error) {
|
|||
// g : A GuildParams struct with the values Name, Region and VerificationLevel defined.
|
||||
func (s *Session) GuildEdit(guildID string, g GuildParams) (st *Guild, err error) {
|
||||
|
||||
// Bounds checking for VerificationLevel, interval: [0, 3]
|
||||
// Bounds checking for VerificationLevel, interval: [0, 4]
|
||||
if g.VerificationLevel != nil {
|
||||
val := *g.VerificationLevel
|
||||
if val < 0 || val > 3 {
|
||||
if val < 0 || val > 4 {
|
||||
err = ErrVerificationLevelBounds
|
||||
return
|
||||
}
|
||||
|
@ -2067,7 +2067,7 @@ func (s *Session) WebhookDeleteWithToken(webhookID, token string) (st *Webhook,
|
|||
// WebhookExecute executes a webhook.
|
||||
// webhookID: The ID of a webhook.
|
||||
// token : The auth token for the webhook
|
||||
// wait : Wait for server to confirm the message arrival
|
||||
// wait : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise)
|
||||
//
|
||||
// If `wait` is `false`, the returned *Message is always empty, because server
|
||||
// does not provide the response data.
|
||||
|
@ -2150,6 +2150,8 @@ func (s *Session) WebhookExecute(webhookID, token string, wait bool, data *Webho
|
|||
// emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier.
|
||||
func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error {
|
||||
|
||||
// emoji such as #⃣ need to have # escaped
|
||||
emojiID = strings.Replace(emojiID, "#", "%23", -1)
|
||||
_, err := s.RequestWithBucketID("PUT", EndpointMessageReaction(channelID, messageID, emojiID, "@me"), nil, EndpointMessageReaction(channelID, "", "", ""))
|
||||
|
||||
return err
|
||||
|
@ -2162,6 +2164,8 @@ func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error
|
|||
// userID : @me or ID of the user to delete the reaction for.
|
||||
func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID string) error {
|
||||
|
||||
// emoji such as #⃣ need to have # escaped
|
||||
emojiID = strings.Replace(emojiID, "#", "%23", -1)
|
||||
_, err := s.RequestWithBucketID("DELETE", EndpointMessageReaction(channelID, messageID, emojiID, userID), nil, EndpointMessageReaction(channelID, "", "", ""))
|
||||
|
||||
return err
|
||||
|
@ -2183,6 +2187,8 @@ func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error {
|
|||
// emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier.
|
||||
// limit : max number of users to return (max 100)
|
||||
func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit int) (st []*User, err error) {
|
||||
// emoji such as #⃣ need to have # escaped
|
||||
emojiID = strings.Replace(emojiID, "#", "%23", -1)
|
||||
uri := EndpointMessageReactions(channelID, messageID, emojiID)
|
||||
|
||||
v := url.Values{}
|
||||
|
|
|
@ -882,6 +882,13 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
|
|||
}
|
||||
case *MessageUpdate:
|
||||
if s.MaxMessageCount != 0 {
|
||||
var old *Message
|
||||
old, err = s.Message(t.ChannelID, t.ID)
|
||||
if err == nil {
|
||||
oldCopy := *old
|
||||
t.BeforeUpdate = &oldCopy
|
||||
}
|
||||
|
||||
err = s.MessageAdd(t.Message)
|
||||
}
|
||||
case *MessageDelete:
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -82,6 +83,9 @@ type Session struct {
|
|||
// The http client used for REST requests
|
||||
Client *http.Client
|
||||
|
||||
// The user agent used for REST APIs
|
||||
UserAgent string
|
||||
|
||||
// Stores the last HeartbeatAck that was recieved (in UTC)
|
||||
LastHeartbeatAck time.Time
|
||||
|
||||
|
@ -196,6 +200,8 @@ const (
|
|||
ChannelTypeGuildVoice
|
||||
ChannelTypeGroupDM
|
||||
ChannelTypeGuildCategory
|
||||
ChannelTypeGuildNews
|
||||
ChannelTypeGuildStore
|
||||
)
|
||||
|
||||
// A Channel holds all data related to an individual Discord channel.
|
||||
|
@ -220,6 +226,10 @@ type Channel struct {
|
|||
// guaranteed to be an ID of a valid message.
|
||||
LastMessageID string `json:"last_message_id"`
|
||||
|
||||
// The timestamp of the last pinned message in the channel.
|
||||
// Empty if the channel has no pinned messages.
|
||||
LastPinTimestamp Timestamp `json:"last_pin_timestamp"`
|
||||
|
||||
// Whether the channel is marked as NSFW.
|
||||
NSFW bool `json:"nsfw"`
|
||||
|
||||
|
@ -247,6 +257,10 @@ type Channel struct {
|
|||
|
||||
// The ID of the parent channel, if the channel is under a category
|
||||
ParentID string `json:"parent_id"`
|
||||
|
||||
// Amount of seconds a user has to wait before sending another message (0-21600)
|
||||
// bots, as well as users with the permission manage_messages or manage_channel, are unaffected
|
||||
RateLimitPerUser int `json:"rate_limit_per_user"`
|
||||
}
|
||||
|
||||
// Mention returns a string which mentions the channel
|
||||
|
@ -283,6 +297,7 @@ type Emoji struct {
|
|||
Managed bool `json:"managed"`
|
||||
RequireColons bool `json:"require_colons"`
|
||||
Animated bool `json:"animated"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
|
||||
// MessageFormat returns a correctly formatted Emoji for use in Message content and embeds
|
||||
|
@ -312,12 +327,13 @@ func (e *Emoji) APIName() string {
|
|||
// VerificationLevel type definition
|
||||
type VerificationLevel int
|
||||
|
||||
// Constants for VerificationLevel levels from 0 to 3 inclusive
|
||||
// Constants for VerificationLevel levels from 0 to 4 inclusive
|
||||
const (
|
||||
VerificationLevelNone VerificationLevel = iota
|
||||
VerificationLevelLow
|
||||
VerificationLevelMedium
|
||||
VerificationLevelHigh
|
||||
VerificationLevelVeryHigh
|
||||
)
|
||||
|
||||
// ExplicitContentFilterLevel type definition
|
||||
|
@ -339,6 +355,17 @@ const (
|
|||
MfaLevelElevated
|
||||
)
|
||||
|
||||
// PremiumTier type definition
|
||||
type PremiumTier int
|
||||
|
||||
// Constants for PremiumTier levels from 0 to 3 inclusive
|
||||
const (
|
||||
PremiumTierNone PremiumTier = iota
|
||||
PremiumTier1
|
||||
PremiumTier2
|
||||
PremiumTier3
|
||||
)
|
||||
|
||||
// A Guild holds all data related to a specific Discord Guild. Guilds are also
|
||||
// sometimes referred to as Servers in the Discord client.
|
||||
type Guild struct {
|
||||
|
@ -443,6 +470,34 @@ type Guild struct {
|
|||
|
||||
// The Channel ID to which system messages are sent (eg join and leave messages)
|
||||
SystemChannelID string `json:"system_channel_id"`
|
||||
|
||||
// the vanity url code for the guild
|
||||
VanityURLCode string `json:"vanity_url_code"`
|
||||
|
||||
// the description for the guild
|
||||
Description string `json:"description"`
|
||||
|
||||
// The hash of the guild's banner
|
||||
Banner string `json:"banner"`
|
||||
|
||||
// The premium tier of the guild
|
||||
PremiumTier PremiumTier `json:"premium_tier"`
|
||||
|
||||
// The total number of users currently boosting this server
|
||||
PremiumSubscriptionCount int `json:"premium_subscription_count"`
|
||||
}
|
||||
|
||||
// IconURL returns a URL to the guild's icon.
|
||||
func (g *Guild) IconURL() string {
|
||||
if g.Icon == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(g.Icon, "a_") {
|
||||
return EndpointGuildIconAnimated(g.ID, g.Icon)
|
||||
}
|
||||
|
||||
return EndpointGuildIcon(g.ID, g.Icon)
|
||||
}
|
||||
|
||||
// A UserGuild holds a brief version of a Guild
|
||||
|
@ -617,6 +672,9 @@ type Member struct {
|
|||
|
||||
// A list of IDs of the roles which are possessed by the member.
|
||||
Roles []string `json:"roles"`
|
||||
|
||||
// When the user used their Nitro boost on the server
|
||||
PremiumSince Timestamp `json:"premium_since"`
|
||||
}
|
||||
|
||||
// Mention creates a member mention
|
||||
|
@ -872,6 +930,7 @@ const (
|
|||
PermissionVoiceDeafenMembers
|
||||
PermissionVoiceMoveMembers
|
||||
PermissionVoiceUseVAD
|
||||
PermissionVoicePrioritySpeaker = 1 << (iota + 2)
|
||||
)
|
||||
|
||||
// Constants for general management.
|
||||
|
@ -907,7 +966,8 @@ const (
|
|||
PermissionVoiceMuteMembers |
|
||||
PermissionVoiceDeafenMembers |
|
||||
PermissionVoiceMoveMembers |
|
||||
PermissionVoiceUseVAD
|
||||
PermissionVoiceUseVAD |
|
||||
PermissionVoicePrioritySpeaker
|
||||
PermissionAllChannel = PermissionAllText |
|
||||
PermissionAllVoice |
|
||||
PermissionCreateInstantInvite |
|
||||
|
@ -956,7 +1016,7 @@ const (
|
|||
ErrCodeMissingAccess = 50001
|
||||
ErrCodeInvalidAccountType = 50002
|
||||
ErrCodeCannotExecuteActionOnDMChannel = 50003
|
||||
ErrCodeEmbedCisabled = 50004
|
||||
ErrCodeEmbedDisabled = 50004
|
||||
ErrCodeCannotEditFromAnotherUser = 50005
|
||||
ErrCodeCannotSendEmptyMessage = 50006
|
||||
ErrCodeCannotSendMessagesToThisUser = 50007
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package discordgo
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord.
|
||||
func SnowflakeTimestamp(ID string) (t time.Time, err error) {
|
||||
i, err := strconv.ParseInt(ID, 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
timestamp := (i >> 22) + 1420070400000
|
||||
t = time.Unix(timestamp/1000, 0)
|
||||
return
|
||||
}
|
|
@ -243,6 +243,7 @@ type voiceOP2 struct {
|
|||
Port int `json:"port"`
|
||||
Modes []string `json:"modes"`
|
||||
HeartbeatInterval time.Duration `json:"heartbeat_interval"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
// WaitUntilConnected waits for the Voice Connection to
|
||||
|
@ -542,7 +543,7 @@ func (v *VoiceConnection) udpOpen() (err error) {
|
|||
return fmt.Errorf("empty endpoint")
|
||||
}
|
||||
|
||||
host := strings.TrimSuffix(v.endpoint, ":80") + ":" + strconv.Itoa(v.op2.Port)
|
||||
host := v.op2.IP + ":" + strconv.Itoa(v.op2.Port)
|
||||
addr, err := net.ResolveUDPAddr("udp", host)
|
||||
if err != nil {
|
||||
v.log(LogWarning, "error resolving udp host %s, %s", host, err)
|
||||
|
@ -593,7 +594,7 @@ func (v *VoiceConnection) udpOpen() (err error) {
|
|||
}
|
||||
|
||||
// Grab port from position 68 and 69
|
||||
port := binary.LittleEndian.Uint16(rb[68:70])
|
||||
port := binary.BigEndian.Uint16(rb[68:70])
|
||||
|
||||
// Take the data from above and send it back to Discord to finalize
|
||||
// the UDP connection handshake.
|
||||
|
|
|
@ -261,7 +261,6 @@ type heartbeatOp struct {
|
|||
|
||||
type helloOp struct {
|
||||
HeartbeatInterval time.Duration `json:"heartbeat_interval"`
|
||||
Trace []string `json:"_trace"`
|
||||
}
|
||||
|
||||
// FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart.
|
||||
|
@ -615,11 +614,7 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
|
|||
voice.session = s
|
||||
voice.Unlock()
|
||||
|
||||
// Send the request to Discord that we want to join the voice channel
|
||||
data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
|
||||
s.wsMutex.Lock()
|
||||
err = s.wsConn.WriteJSON(data)
|
||||
s.wsMutex.Unlock()
|
||||
err = s.ChannelVoiceJoinManual(gID, cID, mute, deaf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -640,22 +635,25 @@ func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *Voi
|
|||
// This should only be used when the VoiceServerUpdate will be intercepted and used elsewhere.
|
||||
//
|
||||
// gID : Guild ID of the channel to join.
|
||||
// cID : Channel ID of the channel to join.
|
||||
// cID : Channel ID of the channel to join, leave empty to disconnect.
|
||||
// mute : If true, you will be set to muted upon joining.
|
||||
// deaf : If true, you will be set to deafened upon joining.
|
||||
func (s *Session) ChannelVoiceJoinManual(gID, cID string, mute, deaf bool) (err error) {
|
||||
|
||||
s.log(LogInformational, "called")
|
||||
|
||||
var channelID *string
|
||||
if cID == "" {
|
||||
channelID = nil
|
||||
} else {
|
||||
channelID = &cID
|
||||
}
|
||||
|
||||
// Send the request to Discord that we want to join the voice channel
|
||||
data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
|
||||
data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, channelID, mute, deaf}}
|
||||
s.wsMutex.Lock()
|
||||
err = s.wsConn.WriteJSON(data)
|
||||
s.wsMutex.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
env:
|
||||
- GO111MODULE=on
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
|
@ -9,6 +14,7 @@ builds:
|
|||
- env:
|
||||
- CGO_ENABLED=0
|
||||
main: ./cmd/tengomin/main.go
|
||||
id: tengomin
|
||||
binary: tengomin
|
||||
goos:
|
||||
- darwin
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package stdlib
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/d5/tengo/objects"
|
||||
)
|
||||
|
||||
var base64Module = map[string]objects.Object{
|
||||
"encode": &objects.UserFunction{Value: FuncAYRS(base64.StdEncoding.EncodeToString)},
|
||||
"decode": &objects.UserFunction{Value: FuncASRYE(base64.StdEncoding.DecodeString)},
|
||||
|
||||
"raw_encode": &objects.UserFunction{Value: FuncAYRS(base64.RawStdEncoding.EncodeToString)},
|
||||
"raw_decode": &objects.UserFunction{Value: FuncASRYE(base64.RawStdEncoding.DecodeString)},
|
||||
|
||||
"url_encode": &objects.UserFunction{Value: FuncAYRS(base64.URLEncoding.EncodeToString)},
|
||||
"url_decode": &objects.UserFunction{Value: FuncASRYE(base64.URLEncoding.DecodeString)},
|
||||
|
||||
"raw_url_encode": &objects.UserFunction{Value: FuncAYRS(base64.RawURLEncoding.EncodeToString)},
|
||||
"raw_url_decode": &objects.UserFunction{Value: FuncASRYE(base64.RawURLEncoding.DecodeString)},
|
||||
}
|
|
@ -11,4 +11,6 @@ var BuiltinModules = map[string]map[string]objects.Object{
|
|||
"rand": randModule,
|
||||
"fmt": fmtModule,
|
||||
"json": jsonModule,
|
||||
"base64": base64Module,
|
||||
"hex": hexModule,
|
||||
}
|
||||
|
|
|
@ -1036,6 +1036,29 @@ func FuncAYRIE(fn func([]byte) (int, error)) objects.CallableFunc {
|
|||
}
|
||||
}
|
||||
|
||||
// FuncAYRS transform a function of 'func([]byte) string' signature
|
||||
// into CallableFunc type.
|
||||
func FuncAYRS(fn func([]byte) string) objects.CallableFunc {
|
||||
return func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 1 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
y1, ok := objects.ToByteSlice(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidArgumentType{
|
||||
Name: "first",
|
||||
Expected: "bytes(compatible)",
|
||||
Found: args[0].TypeName(),
|
||||
}
|
||||
}
|
||||
|
||||
res := fn(y1)
|
||||
|
||||
return &objects.String{Value: res}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FuncASRIE transform a function of 'func(string) (int, error)' signature
|
||||
// into CallableFunc type.
|
||||
func FuncASRIE(fn func(string) (int, error)) objects.CallableFunc {
|
||||
|
@ -1062,6 +1085,36 @@ func FuncASRIE(fn func(string) (int, error)) objects.CallableFunc {
|
|||
}
|
||||
}
|
||||
|
||||
// FuncASRYE transform a function of 'func(string) ([]byte, error)' signature
|
||||
// into CallableFunc type.
|
||||
func FuncASRYE(fn func(string) ([]byte, error)) objects.CallableFunc {
|
||||
return func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 1 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
s1, ok := objects.ToString(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidArgumentType{
|
||||
Name: "first",
|
||||
Expected: "string(compatible)",
|
||||
Found: args[0].TypeName(),
|
||||
}
|
||||
}
|
||||
|
||||
res, err := fn(s1)
|
||||
if err != nil {
|
||||
return wrapError(err), nil
|
||||
}
|
||||
|
||||
if len(res) > tengo.MaxBytesLen {
|
||||
return nil, objects.ErrBytesLimit
|
||||
}
|
||||
|
||||
return &objects.Bytes{Value: res}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FuncAIRSsE transform a function of 'func(int) ([]string, error)' signature
|
||||
// into CallableFunc type.
|
||||
func FuncAIRSsE(fn func(int) ([]string, error)) objects.CallableFunc {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package stdlib
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/d5/tengo/objects"
|
||||
)
|
||||
|
||||
var hexModule = map[string]objects.Object{
|
||||
"encode": &objects.UserFunction{Value: FuncAYRS(hex.EncodeToString)},
|
||||
"decode": &objects.UserFunction{Value: FuncASRYE(hex.DecodeString)},
|
||||
}
|
|
@ -15,7 +15,7 @@ github.com/Philipp15b/go-steam/protocol/steamlang
|
|||
github.com/Philipp15b/go-steam/rwu
|
||||
github.com/Philipp15b/go-steam/socialcache
|
||||
github.com/Philipp15b/go-steam/steamid
|
||||
# github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
|
||||
# github.com/Rhymen/go-whatsapp v0.0.3-0.20191003184814-fc3f792c814c
|
||||
github.com/Rhymen/go-whatsapp
|
||||
github.com/Rhymen/go-whatsapp/binary
|
||||
github.com/Rhymen/go-whatsapp/binary/proto
|
||||
|
@ -23,9 +23,9 @@ github.com/Rhymen/go-whatsapp/binary/token
|
|||
github.com/Rhymen/go-whatsapp/crypto/cbc
|
||||
github.com/Rhymen/go-whatsapp/crypto/curve25519
|
||||
github.com/Rhymen/go-whatsapp/crypto/hkdf
|
||||
# github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40
|
||||
# github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20191026232317-01823f4ebba4
|
||||
github.com/bwmarrin/discordgo
|
||||
# github.com/d5/tengo v1.24.3
|
||||
# github.com/d5/tengo v1.24.8
|
||||
github.com/d5/tengo
|
||||
github.com/d5/tengo/compiler
|
||||
github.com/d5/tengo/compiler/ast
|
||||
|
|
Loading…
Reference in New Issue