adc: some basic protocol understanding
--HG-- branch : adc
This commit is contained in:
parent
931b00a797
commit
c4c6021c85
143
AdcProtocol.go
143
AdcProtocol.go
@ -1,12 +1,32 @@
|
|||||||
package libnmdc
|
package libnmdc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type adcState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
adcStateProtocol adcState = 0
|
||||||
|
adcStateIdentify adcState = 1
|
||||||
|
adcStateVerify adcState = 2
|
||||||
|
adcStateNormal adcState = 3
|
||||||
|
adcStateData adcState = 4
|
||||||
|
)
|
||||||
|
|
||||||
type AdcProtocol struct {
|
type AdcProtocol struct {
|
||||||
hc *HubConnection
|
hc *HubConnection
|
||||||
|
state adcState
|
||||||
|
sid string
|
||||||
|
supports map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAdcProtocol(hc *HubConnection) Protocol {
|
func NewAdcProtocol(hc *HubConnection) Protocol {
|
||||||
proto := AdcProtocol{}
|
proto := AdcProtocol{
|
||||||
proto.hc = hc
|
hc: hc,
|
||||||
|
state: adcStateProtocol,
|
||||||
|
supports: make(map[string]struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
// Start logging in
|
// Start logging in
|
||||||
hc.SayRaw("HSUP ADBASE ADTIGR\n")
|
hc.SayRaw("HSUP ADBASE ADTIGR\n")
|
||||||
@ -16,6 +36,123 @@ func NewAdcProtocol(hc *HubConnection) Protocol {
|
|||||||
|
|
||||||
func (this *AdcProtocol) ProcessCommand(msg string) {
|
func (this *AdcProtocol) ProcessCommand(msg string) {
|
||||||
this.hc.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: msg})
|
this.hc.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: msg})
|
||||||
|
|
||||||
|
if len(msg) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(msg, " ")
|
||||||
|
switch parts[0] {
|
||||||
|
|
||||||
|
case "ISUP":
|
||||||
|
if !(this.state == adcStateProtocol || this.state == adcStateNormal) {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, supportflag := range parts[1:] {
|
||||||
|
if len(supportflag) < 2 {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if supportflag[0:2] == "AD" {
|
||||||
|
this.supports[supportflag[2:]] = struct{}{}
|
||||||
|
} else if supportflag[0:2] == "RM" {
|
||||||
|
delete(this.supports, supportflag[2:])
|
||||||
|
} else {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if this.state == adcStateProtocol {
|
||||||
|
this.state = adcStateIdentify
|
||||||
|
}
|
||||||
|
|
||||||
|
case "ISID":
|
||||||
|
if this.state != adcStateIdentify {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.sid = parts[1]
|
||||||
|
|
||||||
|
case "IINF":
|
||||||
|
flags := make(map[string]string)
|
||||||
|
for _, flag := range parts[1:] {
|
||||||
|
if len(flag) < 2 {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
flags[flag[0:2]] = flag[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibilities: User MyINFO (Normal state), or, hub telling information about itself (Identify->Normal state)
|
||||||
|
if (this.state == adcStateIdentify || this.state == adcStateVerify) && flags["CT"] == "32" {
|
||||||
|
// Hub telling information about itself
|
||||||
|
this.handleInfo(flags)
|
||||||
|
|
||||||
|
// Transition to state VERIFY and send our own info
|
||||||
|
this.hc.SayRaw("BINF " + this.escape(this.sid) + " GARBAGE") // FIXME send a real info string
|
||||||
|
this.state = adcStateVerify
|
||||||
|
|
||||||
|
} else if this.state == adcStateNormal {
|
||||||
|
// OK
|
||||||
|
this.handleInfo(flags)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.malformed(parts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case "IGPA":
|
||||||
|
//
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.malformed(parts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AdcProtocol) handleInfo(flags map[string]string) {
|
||||||
|
if flags["CT"] == "32" {
|
||||||
|
|
||||||
|
// IINF DEADCH++\sTest\shub VE2.12.1\s(r"[unknown]")\sRelease HI1 NIADCH++ APADCH++ CT32
|
||||||
|
// AP: extension 3.24 "Application and version separation in INF"
|
||||||
|
// HI:
|
||||||
|
|
||||||
|
// Hub properties updated
|
||||||
|
hubName, ok := flags["DE"]
|
||||||
|
if ok {
|
||||||
|
this.hc.HubName = this.unescape(hubName)
|
||||||
|
this.hc.processEvent(HubEvent{EventType: EVENT_HUBNAME_CHANGED, Nick: this.hc.HubName})
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// User MyINFO
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AdcProtocol) enterNormalState() {
|
||||||
|
this.state = adcStateNormal
|
||||||
|
this.hc.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTED})
|
||||||
|
this.hc.State = CONNECTIONSTATE_CONNECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AdcProtocol) malformed(parts []string) {
|
||||||
|
this.hc.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Ignoring malformed, unhandled, or out-of-state protocol command '" + parts[0] + "'"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AdcProtocol) escape(plaintext string) string {
|
||||||
|
// The string "\s" escapes space, "\n" newline and "\\" backslash. This version of the protocol reserves all other escapes for future use; any message containing unknown escapes must be discarded.
|
||||||
|
v1 := strings.Replace(plaintext, `\`, `\\`, -1)
|
||||||
|
v2 := strings.Replace(v1, "\n", `\n`, -1)
|
||||||
|
return strings.Replace(v2, " ", `\s`, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *AdcProtocol) unescape(encoded string) string {
|
||||||
|
v1 := strings.Replace(encoded, `\s`, " ", -1)
|
||||||
|
v2 := strings.Replace(v1, `\n`, "\n", -1)
|
||||||
|
return strings.Replace(v2, `\\`, `\`, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *AdcProtocol) SayPublic(msg string) {
|
func (this *AdcProtocol) SayPublic(msg string) {
|
||||||
|
Loading…
Reference in New Issue
Block a user