Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51b08dad3d | |||
| 1a3e4fe072 | |||
| 086281dab2 | |||
| 7392cbbea5 | |||
| 265c0a43ce | |||
| 417deff347 | |||
| a996f1668c | |||
| 9b290ebb96 |
2
.hgtags
2
.hgtags
@@ -10,3 +10,5 @@ da9f123633f9c28be6435ed7898139665d4c39d9 nmdc-log-service-1.0.2
|
|||||||
cb86f3a40115cc46f450c0c83fd9b9d3b740e820 nmdc-log-service-1.0.4
|
cb86f3a40115cc46f450c0c83fd9b9d3b740e820 nmdc-log-service-1.0.4
|
||||||
cb86f3a40115cc46f450c0c83fd9b9d3b740e820 libnmdc-r6
|
cb86f3a40115cc46f450c0c83fd9b9d3b740e820 libnmdc-r6
|
||||||
71343a2c641a438206d30ea7e75dc89a11dbef00 libnmdc-r7
|
71343a2c641a438206d30ea7e75dc89a11dbef00 libnmdc-r7
|
||||||
|
b0e57a5fcffdf4102d669db51a3648ddf66a0792 libnmdc-r8
|
||||||
|
e7c2c71ef24b386add728fad35fff4a996fccbac libnmdc-r9
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package libnmdc
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -74,11 +75,15 @@ func (this *HubConnection) userJoined_NameOnly(nick string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *HubConnection) userJoined_Full(uinf *UserInfo) {
|
func (this *HubConnection) userJoined_Full(uinf *UserInfo) {
|
||||||
if !this.UserExists(uinf.Nick) {
|
// n.b. also called when we get a replacement MyINFO for someone
|
||||||
this.userLock.Lock()
|
this.userLock.Lock()
|
||||||
defer this.userLock.Unlock()
|
defer this.userLock.Unlock()
|
||||||
|
|
||||||
|
_, userExisted := this.users[uinf.Nick] // don't use UserExists as it would deadlock the mutex
|
||||||
|
|
||||||
this.users[uinf.Nick] = *uinf
|
this.users[uinf.Nick] = *uinf
|
||||||
|
|
||||||
|
if !userExisted {
|
||||||
this.processEvent(HubEvent{EventType: EVENT_USER_JOINED, Nick: uinf.Nick})
|
this.processEvent(HubEvent{EventType: EVENT_USER_JOINED, Nick: uinf.Nick})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,9 +245,29 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
this.Hco.Address = HubAddress(commandParts[1])
|
this.Hco.Address = HubAddress(commandParts[1])
|
||||||
this.conn.Close() // we'll reconnect onto the new address
|
this.conn.Close() // we'll reconnect onto the new address
|
||||||
|
|
||||||
|
case "$UserCommand":
|
||||||
|
// $UserCommand 1 1 Group chat\New group chat$<%[mynick]> !groupchat_new||
|
||||||
|
if rx_userCommand.MatchString(commandParts[1]) {
|
||||||
|
usc := rx_userCommand.FindStringSubmatch(commandParts[1])
|
||||||
|
|
||||||
|
typeInt, _ := strconv.Atoi(usc[1])
|
||||||
|
contextInt, _ := strconv.Atoi(usc[2])
|
||||||
|
|
||||||
|
uscStruct := UserCommand{
|
||||||
|
Type: UserCommandType(typeInt),
|
||||||
|
Context: UserCommandContext(contextInt),
|
||||||
|
Message: usc[3],
|
||||||
|
Command: NMDCUnescape(usc[4]),
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processEvent(HubEvent{EventType: EVENT_USERCOMMAND, UserCommand: &uscStruct})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Malformed usercommand '" + commandParts[1] + "'"})
|
||||||
|
}
|
||||||
|
|
||||||
// IGNORABLE COMMANDS
|
// IGNORABLE COMMANDS
|
||||||
case "$Supports":
|
case "$Supports":
|
||||||
case "$UserCommand": // TODO $UserCommand 1 1 Group chat\New group chat$<%[mynick]> !groupchat_new||
|
|
||||||
case "$HubTopic":
|
case "$HubTopic":
|
||||||
case "$Search":
|
case "$Search":
|
||||||
case "$ConnectToMe":
|
case "$ConnectToMe":
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const (
|
|||||||
EVENT_CONNECTION_STATE_CHANGED = 8
|
EVENT_CONNECTION_STATE_CHANGED = 8
|
||||||
EVENT_HUBNAME_CHANGED = 9
|
EVENT_HUBNAME_CHANGED = 9
|
||||||
EVENT_DEBUG_MESSAGE = 10
|
EVENT_DEBUG_MESSAGE = 10
|
||||||
|
EVENT_USERCOMMAND = 11
|
||||||
)
|
)
|
||||||
|
|
||||||
type HubEventType int
|
type HubEventType int
|
||||||
@@ -20,4 +21,5 @@ type HubEvent struct {
|
|||||||
Nick string
|
Nick string
|
||||||
Message string
|
Message string
|
||||||
StateChange ConnectionState
|
StateChange ConnectionState
|
||||||
|
UserCommand *UserCommand
|
||||||
}
|
}
|
||||||
|
|||||||
26
UserCommand.go
Normal file
26
UserCommand.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package libnmdc
|
||||||
|
|
||||||
|
type UserCommandType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
USERCOMMAND_TYPE_SEPARATOR UserCommandType = 0
|
||||||
|
USERCOMMAND_TYPE_RAW UserCommandType = 1
|
||||||
|
USERCOMMAND_TYPE_NICKLIMITED UserCommandType = 2
|
||||||
|
USERCOMMAND_TYPE_CLEARALL UserCommandType = 255
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserCommandContext uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
USERCOMMAND_CONTEXT_HUB UserCommandContext = 1
|
||||||
|
USERCOMMAND_CONTEXT_USER UserCommandContext = 2
|
||||||
|
USERCOMMAND_CONTEXT_SEARCH UserCommandContext = 4
|
||||||
|
USERCOMMAND_CONTEXT_FILELIST UserCommandContext = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserCommand struct {
|
||||||
|
Type UserCommandType
|
||||||
|
Context UserCommandContext
|
||||||
|
Message string
|
||||||
|
Command string
|
||||||
|
}
|
||||||
45
UserInfo.go
45
UserInfo.go
@@ -56,12 +56,19 @@ var rx_myinfo_notag *regexp.Regexp
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// $ALL <nick> <description>$ $<connection><flag>$<e-mail>$<sharesize>$
|
// $ALL <nick> <description>$ $<connection><flag>$<e-mail>$<sharesize>$
|
||||||
rx_myinfo = regexp.MustCompile("(?ms)^\\$ALL ([^ ]+) ([^<]*)<([^,]*)V:([^,]+),M:(.),H:([0-9]+)/([0-9]+)/([0-9]+),S:([0-9]+)>\\$.\\$(.+?)(.)\\$([^$]*)\\$([0-9]*)\\$$")
|
|
||||||
rx_myinfo_notag = regexp.MustCompile("(?ms)^\\$ALL ([^ ]+) ([^$]*)\\$.\\$(.*)(.)\\$([^$]*)\\$([0-9]*)\\$$") // Fallback for no tag
|
HEAD := `(?ms)^\$ALL ([^ ]+) `
|
||||||
|
FOOT := `\$.\$([^$]+)\$([^$]*)\$([0-9]*)\$$`
|
||||||
|
|
||||||
|
rx_myinfo = regexp.MustCompile(HEAD + `([^<]*)<(.+?) V:([^,]+),M:(.),H:([0-9]+)/([0-9]+)/([0-9]+),S:([0-9]+)>` + FOOT)
|
||||||
|
rx_myinfo_notag = regexp.MustCompile(HEAD + `([^$]*)` + FOOT) // Fallback for no tag
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sample := "$ALL Betty description<ApexDC++ V:1.4.3,M:P,H:9/0/2,S:1>$ $0.01\x01$xyz@xyz.com$53054999578$"
|
sample := ""
|
||||||
sample = "$ALL ivysaur80 $P$10A$$0$"
|
// sample = "$ALL Betty description<ApexDC++ V:1.4.3,M:P,H:9/0/2,S:1>$ $0.01\x01$xyz@xyz.com$53054999578$"
|
||||||
|
// sample = "$ALL ivysaur80 $P$10A$$0$"
|
||||||
|
// sample = "$ALL SHINY_IVYSAUR <ncdc V:1.19.1-12-g5561,M:P,H:1/0/0,S:10>$ $0.005Q$$0$"
|
||||||
|
// sample = "$ALL mappu desccccc<HexChat V:2.12.1,M:P,H:1/0/0,S:0>$ $p$$0$"
|
||||||
|
|
||||||
u := UserInfo{}
|
u := UserInfo{}
|
||||||
err := u.fromMyINFO(sample)
|
err := u.fromMyINFO(sample)
|
||||||
@@ -71,7 +78,7 @@ func init() {
|
|||||||
fmt.Printf("%+v\n", u)
|
fmt.Printf("%+v\n", u)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(1)
|
panic("")
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +100,7 @@ func maybeParse(str string, dest *uint64, default_val uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UserInfo) fromMyINFO(protomsg string) error {
|
func (this *UserInfo) fromMyINFO(protomsg string) error {
|
||||||
|
|
||||||
// Normal format (with tag in exact V/M/H/S order)
|
// Normal format (with tag in exact V/M/H/S order)
|
||||||
matches := rx_myinfo.FindStringSubmatch(protomsg)
|
matches := rx_myinfo.FindStringSubmatch(protomsg)
|
||||||
if matches != nil {
|
if matches != nil {
|
||||||
@@ -105,10 +113,14 @@ func (this *UserInfo) fromMyINFO(protomsg string) error {
|
|||||||
maybeParse(matches[7], &this.HubsRegistered, 0)
|
maybeParse(matches[7], &this.HubsRegistered, 0)
|
||||||
maybeParse(matches[8], &this.HubsOperator, 0)
|
maybeParse(matches[8], &this.HubsOperator, 0)
|
||||||
maybeParse(matches[9], &this.Slots, 0)
|
maybeParse(matches[9], &this.Slots, 0)
|
||||||
this.Speed = matches[10]
|
if len(matches[10]) > 1 {
|
||||||
this.Flag = UserFlag(matches[11][0])
|
this.Speed = matches[10][:len(matches[10])-2]
|
||||||
this.Email = NMDCUnescape(matches[12])
|
} else {
|
||||||
maybeParse(matches[13], &this.ShareSize, 0)
|
this.Speed = ""
|
||||||
|
}
|
||||||
|
this.Flag = UserFlag(matches[10][len(matches[10])-1])
|
||||||
|
this.Email = NMDCUnescape(matches[11])
|
||||||
|
maybeParse(matches[12], &this.ShareSize, 0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -125,14 +137,21 @@ func (this *UserInfo) fromMyINFO(protomsg string) error {
|
|||||||
this.HubsRegistered = 0
|
this.HubsRegistered = 0
|
||||||
this.HubsOperator = 0
|
this.HubsOperator = 0
|
||||||
this.Slots = 0
|
this.Slots = 0
|
||||||
this.Speed = matches[3]
|
|
||||||
this.Flag = UserFlag(matches[4][0])
|
if len(matches[3]) > 1 {
|
||||||
this.Email = NMDCUnescape(matches[5])
|
this.Speed = matches[3][:len(matches[3])-2]
|
||||||
maybeParse(matches[6], &this.ShareSize, 0)
|
} else {
|
||||||
|
this.Speed = ""
|
||||||
|
}
|
||||||
|
this.Flag = UserFlag(matches[3][len(matches[3])-1])
|
||||||
|
this.Email = NMDCUnescape(matches[4])
|
||||||
|
maybeParse(matches[5], &this.ShareSize, 0)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("PARSE: malformed\n")
|
||||||
|
|
||||||
// Couldn't get anything out of it...
|
// Couldn't get anything out of it...
|
||||||
return errors.New("Malformed MyINFO")
|
return errors.New("Malformed MyINFO")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,13 @@ Tags: nmdc
|
|||||||
|
|
||||||
=CHANGELOG=
|
=CHANGELOG=
|
||||||
|
|
||||||
|
2016-10-08 r10
|
||||||
|
- Feature: Support `$UserCommand`
|
||||||
|
|
||||||
|
2016-08-27 r9
|
||||||
|
- Fix an issue with parsing MyINFO strings with zero-length speed descriptions
|
||||||
|
- Fix an issue with not storing updated profile information
|
||||||
|
|
||||||
2016-05-10 r8
|
2016-05-10 r8
|
||||||
- Enhancement: Separate `ClientTag` and `ClientVersion` in `UserInfo` structs
|
- Enhancement: Separate `ClientTag` and `ClientVersion` in `UserInfo` structs
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ const (
|
|||||||
var rx_protocolMessage *regexp.Regexp
|
var rx_protocolMessage *regexp.Regexp
|
||||||
var rx_publicChat *regexp.Regexp
|
var rx_publicChat *regexp.Regexp
|
||||||
var rx_incomingTo *regexp.Regexp
|
var rx_incomingTo *regexp.Regexp
|
||||||
|
var rx_userCommand *regexp.Regexp
|
||||||
var ErrNotConnected error = errors.New("Not connected")
|
var ErrNotConnected error = errors.New("Not connected")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rx_protocolMessage = regexp.MustCompile("(?ms)^[^|]*\\|")
|
rx_protocolMessage = regexp.MustCompile("(?ms)^[^|]*\\|")
|
||||||
rx_publicChat = regexp.MustCompile("(?ms)^<([^>]*)> (.*)$")
|
rx_publicChat = regexp.MustCompile("(?ms)^<([^>]*)> (.*)$")
|
||||||
rx_incomingTo = regexp.MustCompile("(?ms)^([^ ]+) From: ([^ ]+) \\$<([^>]*)> (.*)")
|
rx_incomingTo = regexp.MustCompile("(?ms)^([^ ]+) From: ([^ ]+) \\$<([^>]*)> (.*)")
|
||||||
|
rx_userCommand = regexp.MustCompile(`(?ms)^(\d+) (\d+)\s?([^\$]*)\$?(.*)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NMDCUnescape(encoded string) string {
|
func NMDCUnescape(encoded string) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user