libnmdc: optional synchronous-based API instead of channel-based API
This commit is contained in:
parent
e3a92da5f6
commit
ba378a8245
@ -75,11 +75,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HubConnectionOptions struct {
|
type HubConnectionOptions struct {
|
||||||
Address HubAddress
|
Address HubAddress
|
||||||
SkipVerifyTLS bool // using a negative verb, because bools default to false
|
SkipVerifyTLS bool // using a negative verb, because bools default to false
|
||||||
Self UserInfo
|
Self UserInfo
|
||||||
NickPassword string
|
NickPassword string
|
||||||
|
|
||||||
|
// Returning messages in async mode
|
||||||
NumEventsToBuffer uint
|
NumEventsToBuffer uint
|
||||||
|
OnEvent chan HubEvent
|
||||||
|
|
||||||
|
// Returning messages in sync mode
|
||||||
|
OnEventSync func(HubEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HubConnection struct {
|
type HubConnection struct {
|
||||||
@ -92,7 +98,7 @@ type HubConnection struct {
|
|||||||
Users map[string]UserInfo
|
Users map[string]UserInfo
|
||||||
|
|
||||||
// Streamed events
|
// Streamed events
|
||||||
OnEvent chan HubEvent
|
processEvent func(HubEvent)
|
||||||
|
|
||||||
// Private state
|
// Private state
|
||||||
conn net.Conn // this is an interface
|
conn net.Conn // this is an interface
|
||||||
@ -148,7 +154,7 @@ func (this *HubConnection) userJoined_NameOnly(nick string) {
|
|||||||
_, already_existed := this.Users[nick]
|
_, already_existed := this.Users[nick]
|
||||||
if !already_existed {
|
if !already_existed {
|
||||||
this.Users[nick] = *NewUserInfo(nick)
|
this.Users[nick] = *NewUserInfo(nick)
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_USER_JOINED, Nick: nick}
|
this.processEvent(HubEvent{EventType: EVENT_USER_JOINED, Nick: nick})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +162,7 @@ func (this *HubConnection) userJoined_Full(uinf *UserInfo) {
|
|||||||
_, already_existed := this.Users[uinf.Nick]
|
_, already_existed := this.Users[uinf.Nick]
|
||||||
if !already_existed {
|
if !already_existed {
|
||||||
this.Users[uinf.Nick] = *uinf
|
this.Users[uinf.Nick] = *uinf
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_USER_JOINED, Nick: uinf.Nick}
|
this.processEvent(HubEvent{EventType: EVENT_USER_JOINED, Nick: uinf.Nick})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,14 +211,14 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
// ```````````
|
// ```````````
|
||||||
if rx_publicChat.MatchString(message) {
|
if rx_publicChat.MatchString(message) {
|
||||||
pubchat_parts := rx_publicChat.FindStringSubmatch(message)
|
pubchat_parts := rx_publicChat.FindStringSubmatch(message)
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_PUBLIC, Nick: pubchat_parts[1], Message: NMDCUnescape(pubchat_parts[2])}
|
this.processEvent(HubEvent{EventType: EVENT_PUBLIC, Nick: pubchat_parts[1], Message: NMDCUnescape(pubchat_parts[2])})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// System messages
|
// System messages
|
||||||
// ```````````````
|
// ```````````````
|
||||||
if message[0] != '$' {
|
if message[0] != '$' {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_HUB, Nick: this.HubName, Message: NMDCUnescape(message)}
|
this.processEvent(HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_HUB, Nick: this.HubName, Message: NMDCUnescape(message)})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,27 +248,27 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
|
|
||||||
case "$HubName":
|
case "$HubName":
|
||||||
this.HubName = commandParts[1]
|
this.HubName = commandParts[1]
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_HUBNAME_CHANGED, Nick: commandParts[1]}
|
this.processEvent(HubEvent{EventType: EVENT_HUBNAME_CHANGED, Nick: commandParts[1]})
|
||||||
|
|
||||||
case "$ValidateDenide": // sic
|
case "$ValidateDenide": // sic
|
||||||
if len(this.Hco.NickPassword) > 0 {
|
if len(this.Hco.NickPassword) > 0 {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Incorrect password."}
|
this.processEvent(HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Incorrect password."})
|
||||||
} else {
|
} else {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Nick already in use."}
|
this.processEvent(HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Nick already in use."})
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$HubIsFull":
|
case "$HubIsFull":
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Hub is full."}
|
this.processEvent(HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Hub is full."})
|
||||||
|
|
||||||
case "$BadPass":
|
case "$BadPass":
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Incorrect password."}
|
this.processEvent(HubEvent{EventType: EVENT_SYSTEM_MESSAGE_FROM_CONN, Message: "Incorrect password."})
|
||||||
|
|
||||||
case "$GetPass":
|
case "$GetPass":
|
||||||
this.SayRaw("$MyPass " + NMDCEscape(this.Hco.NickPassword) + "|")
|
this.SayRaw("$MyPass " + NMDCEscape(this.Hco.NickPassword) + "|")
|
||||||
|
|
||||||
case "$Quit":
|
case "$Quit":
|
||||||
delete(this.Users, commandParts[1])
|
delete(this.Users, commandParts[1])
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_USER_PART, Nick: commandParts[1]}
|
this.processEvent(HubEvent{EventType: EVENT_USER_PART, Nick: commandParts[1]})
|
||||||
|
|
||||||
case "$MyINFO":
|
case "$MyINFO":
|
||||||
u := UserInfo{}
|
u := UserInfo{}
|
||||||
@ -270,7 +276,7 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
this.userJoined_Full(&u)
|
this.userJoined_Full(&u)
|
||||||
} else {
|
} else {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: err.Error()}
|
this.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: err.Error()})
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$NickList":
|
case "$NickList":
|
||||||
@ -286,20 +292,20 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
if rx_incomingTo.MatchString(commandParts[1]) {
|
if rx_incomingTo.MatchString(commandParts[1]) {
|
||||||
txparts := rx_incomingTo.FindStringSubmatch(commandParts[1])
|
txparts := rx_incomingTo.FindStringSubmatch(commandParts[1])
|
||||||
if txparts[1] == this.Hco.Self.Nick && txparts[2] == txparts[3] {
|
if txparts[1] == this.Hco.Self.Nick && txparts[2] == txparts[3] {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_PRIVATE, Nick: txparts[2], Message: txparts[4]}
|
this.processEvent(HubEvent{EventType: EVENT_PRIVATE, Nick: txparts[2], Message: txparts[4]})
|
||||||
valid = true
|
valid = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Malformed private message '" + commandParts[1] + "'"}
|
this.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Malformed private message '" + commandParts[1] + "'"})
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$UserIP":
|
case "$UserIP":
|
||||||
// Final message in PtokaX connection handshake - trigger connection callback.
|
// Final message in PtokaX connection handshake - trigger connection callback.
|
||||||
// This might not be the case for other hubsofts, though
|
// This might not be the case for other hubsofts, though
|
||||||
if this.State != CONNECTIONSTATE_CONNECTED {
|
if this.State != CONNECTIONSTATE_CONNECTED {
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTED}
|
this.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTED})
|
||||||
this.State = CONNECTIONSTATE_CONNECTED
|
this.State = CONNECTIONSTATE_CONNECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +324,7 @@ func (this *HubConnection) processProtocolMessage(message string) {
|
|||||||
case "$ConnectToMe":
|
case "$ConnectToMe":
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Unhandled protocol command '" + commandParts[0] + "'"}
|
this.processEvent(HubEvent{EventType: EVENT_DEBUG_MESSAGE, Message: "Unhandled protocol command '" + commandParts[0] + "'"})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,7 +356,7 @@ func (this *HubConnection) worker() {
|
|||||||
} else {
|
} else {
|
||||||
this.State = CONNECTIONSTATE_CONNECTING
|
this.State = CONNECTIONSTATE_CONNECTING
|
||||||
this.connValid = true
|
this.connValid = true
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTING}
|
this.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTING})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,7 +375,7 @@ func (this *HubConnection) worker() {
|
|||||||
this.State = CONNECTIONSTATE_DISCONNECTED
|
this.State = CONNECTIONSTATE_DISCONNECTED
|
||||||
this.conn = nil
|
this.conn = nil
|
||||||
this.connValid = false
|
this.connValid = false
|
||||||
this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_DISCONNECTED, Message: err.Error()}
|
this.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_DISCONNECTED, Message: err.Error()})
|
||||||
|
|
||||||
time.Sleep(30 * time.Second) // Wait before reconnect
|
time.Sleep(30 * time.Second) // Wait before reconnect
|
||||||
continue
|
continue
|
||||||
@ -393,26 +399,45 @@ func (this *HubConnection) worker() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connects to an NMDC server, and spawns a background goroutine to handle
|
func (this *HubConnectionOptions) prepareConnection() *HubConnection {
|
||||||
// protocol messages. Client code should select on all the interface channels.
|
|
||||||
func (this *HubConnectionOptions) Connect() *HubConnection {
|
|
||||||
|
|
||||||
if this.Self.ClientTag == "" {
|
if this.Self.ClientTag == "" {
|
||||||
this.Self.ClientTag = "libnmdc.go"
|
this.Self.ClientTag = "libnmdc.go"
|
||||||
}
|
}
|
||||||
if this.NumEventsToBuffer < 1 {
|
|
||||||
this.NumEventsToBuffer = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
hc := HubConnection{
|
hc := HubConnection{
|
||||||
Hco: this,
|
Hco: this,
|
||||||
HubName: "(unknown)",
|
HubName: "(unknown)",
|
||||||
State: CONNECTIONSTATE_DISCONNECTED,
|
State: CONNECTIONSTATE_DISCONNECTED,
|
||||||
Users: make(map[string]UserInfo),
|
Users: make(map[string]UserInfo),
|
||||||
OnEvent: make(chan HubEvent, this.NumEventsToBuffer),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go hc.worker()
|
|
||||||
|
|
||||||
return &hc
|
return &hc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connects to an NMDC server, and spawns a background goroutine to handle
|
||||||
|
// protocol messages. Client code should select on all the interface channels.
|
||||||
|
func (this *HubConnectionOptions) Connect() *HubConnection {
|
||||||
|
|
||||||
|
if this.NumEventsToBuffer < 1 {
|
||||||
|
this.NumEventsToBuffer = 1
|
||||||
|
}
|
||||||
|
if this.OnEvent == nil {
|
||||||
|
this.OnEvent = make(chan HubEvent, this.NumEventsToBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
hc := this.prepareConnection()
|
||||||
|
|
||||||
|
hc.processEvent = func(ev HubEvent) {
|
||||||
|
this.OnEvent <- ev
|
||||||
|
}
|
||||||
|
|
||||||
|
go hc.worker()
|
||||||
|
return hc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connects to an NMDC server, and blocks forever to handle protocol messages.
|
||||||
|
// Client code should supply an event handling function.
|
||||||
|
func (this *HubConnectionOptions) ConnectSync() {
|
||||||
|
hc := this.prepareConnection()
|
||||||
|
hc.worker()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user