37 Commits

Author SHA1 Message Date
32f64690c9 update README 2016-04-04 19:04:27 +12:00
3f66cd93c7 Added tag libnmdc-r5 for changeset 75a78f6a78f2 2016-04-04 19:02:56 +12:00
9b32682c8a libnmdc: support hub-redirects 2016-04-04 19:01:55 +12:00
c9e95df0df libnmdc: fix for previous 2016-04-04 19:01:47 +12:00
a2b94e8724 libnmdc: send protocol-level keepalives 2016-04-04 18:57:50 +12:00
3dfef302ee Added tag nmdc-log-service-1.0.2 for changeset da9f123633f9 2016-04-03 19:24:12 +12:00
611a934a4e nmdc-log-service: readme 2016-04-03 19:24:03 +12:00
1a3617b960 libnmdc: readme 2016-04-03 19:23:14 +12:00
a37b1773d0 Added tag libnmdc-r4 for changeset 050b424a7c5d 2016-04-03 19:22:02 +12:00
09301f138c libnmdc: (comment) 2016-04-03 19:21:32 +12:00
8d7b0b46af libnmdc: fix bugs with buffer splitting 2016-04-03 19:20:58 +12:00
73f6d66cbd libnmdc: reinstate backward-compatibility re new sync api 2016-04-03 18:59:11 +12:00
019f67a7de libnmdc: ensure we always flush protocol commands that happened alongside a disconnection event 2016-04-03 18:54:56 +12:00
debc14cea3 libnmdc: isolate constants 2016-04-03 18:53:14 +12:00
ba378a8245 libnmdc: optional synchronous-based API instead of channel-based API 2016-04-03 18:52:19 +12:00
e3a92da5f6 libnmdc: remove redundant bool=false initialisation (handled in $Lock callback) 2016-04-03 18:38:43 +12:00
99e4ebb842 libnmdc: set our own state before emitting statechange event 2016-04-03 18:38:06 +12:00
4499c7306d libnmdc: clear fullbuffer prior to connection attempt 2016-04-03 18:36:46 +12:00
d391159abe libnmdc: avoid meaningless cast 2016-04-03 18:35:11 +12:00
e111c99886 libnmdc: assert state parameter is set correctly 2016-04-03 18:35:05 +12:00
393f156b0e Added tag nmdc-log-service-1.0.1 for changeset fca41372e400 2016-04-03 13:36:47 +12:00
7cd49c2c8a update README files 2016-04-03 13:36:41 +12:00
163b6623f8 Added tag libnmdc-r3 for changeset d8b64d5527c2 2016-04-03 13:33:48 +12:00
2f0ab758b8 nmdc-log-service: add warning message if on TLS verification disabled 2016-04-03 13:32:19 +12:00
3b71ea3ce3 nmdc-log-service: add missing LF 2016-04-03 13:29:58 +12:00
b0e1c3e5d8 nmdc-log-service: fix opening files on linux 2016-04-03 13:29:49 +12:00
3a67b02bd9 libnmdc: patch wrong test 2016-04-03 13:29:34 +12:00
27c21572b3 libnmdc: use extra variable instead of reflect package 2016-04-03 13:22:09 +12:00
da92afa51e libnmdc: add SkipVerifyTLS option 2016-04-03 13:17:29 +12:00
ec0a781538 libnmdc: fix panic() on connection failure, owing to storing nil in an interface 2016-04-03 13:15:57 +12:00
052c3e2cba nmdc-log-service/build: build with -a 2016-04-03 11:50:37 +12:00
db0e1a5c2f nmdc-log-service: track readme 2016-04-02 14:31:34 +13:00
ead04a1d4d Added tag libnmdc-r2 for changeset 137c1b65039e 2016-04-02 14:28:42 +13:00
f8ac216379 libnmdc: update readme 2016-04-02 14:28:35 +13:00
28ad3c8e6a libnmdc: reintroduce sample client as part of main package 2016-04-02 14:27:48 +13:00
820fa72b77 Added tag nmdc-log-service-1.0.0 for changeset 02a360e95480 2016-04-02 14:22:24 +13:00
f4b868b0c7 Added tag libnmdc-r1 for changeset 945ab4b16d05 2016-04-02 14:22:15 +13:00
8 changed files with 254 additions and 69 deletions

8
.hgtags Normal file
View File

@@ -0,0 +1,8 @@
945ab4b16d05aa084f71bf5da9a3f687e0ec8bbd libnmdc-r1
02a360e95480b97ddad83add5db48b2766339a99 nmdc-log-service-1.0.0
137c1b65039e03c80379826a6efdfd808f6fbc8f libnmdc-r2
d8b64d5527c2a5e4d76872e5bc3d69f7646135c6 libnmdc-r3
fca41372e400853775b02e951f9db91d87f41adb nmdc-log-service-1.0.1
050b424a7c5d5a27c9323c8810f3afbead1f5b96 libnmdc-r4
da9f123633f9c28be6435ed7898139665d4c39d9 nmdc-log-service-1.0.2
75a78f6a78f249a2cd8aa3d29f7e5e6319b4e03b libnmdc-r5

View File

@@ -1,7 +0,0 @@
An NMDC client protocol library for Golang.
- Includes a sample logging client.
- This code hosting site isn't yet compatible with `go get`.
Written in golang
Tags: nmdc

View File

@@ -0,0 +1,33 @@
An NMDC client protocol library for Golang.
- Offers both channel-based and synchronous APIs.
- Includes a sample logging client using the channel-based API.
- This code hosting site isn't (yet) compatible with `go get`.
Written in golang
Tags: nmdc
=CHANGELOG=
2016-04-04 r5
- Enhancement: Support protocol keepalives
- Enhancement: Support hub redirects (`$ForceMove`)
2016-04-03 r4
- Feature: Add synchronous API
- Fix an issue with reading HubConnection's state parameter
- Fix an issue with buffered protocol commands
2016-04-03 r3
- Feature: Add `SkipVerifyTLS` option
- Fix an issue with calling `panic()` if connection failed
2016-04-02 r2
- Enhancement: Support NMDC-over-TLS (NMDCS)
- Fix an issue recieving private messages
- Fix an issue with calling `panic()` if connection failed
- Fix an issue parsing URIs without a specified port
- Move sample content into directory with excluded build
2016-02-12 r1
- Initial public release

View File

@@ -3,6 +3,7 @@ package libnmdc
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
@@ -11,6 +12,12 @@ import (
"time" "time"
) )
const (
DEFAULT_CLIENT_TAG string = "libnmdc.go"
DEFAULT_HUB_NAME string = "(unknown)"
SEND_KEEPALIVE_EVERY time.Duration = 29 * time.Second
)
type ConnectionState int type ConnectionState int
type HubEventType int type HubEventType int
@@ -65,18 +72,25 @@ 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 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: ([^ ]+) \\$<([^>]*)> (.*)")
} }
type HubConnectionOptions struct { type HubConnectionOptions struct {
Address HubAddress Address HubAddress
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
// Returning messages in sync mode
OnEventSync func(HubEvent)
} }
type HubConnection struct { type HubConnection struct {
@@ -89,10 +103,12 @@ type HubConnection struct {
Users map[string]UserInfo Users map[string]UserInfo
// Streamed events // Streamed events
processEvent func(HubEvent)
OnEvent chan HubEvent OnEvent chan HubEvent
// Private state // Private state
conn net.Conn conn net.Conn // this is an interface
connValid bool
sentOurHello bool sentOurHello bool
} }
@@ -144,7 +160,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})
} }
} }
@@ -152,15 +168,19 @@ 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})
} }
} }
// Note that protocol messages are transmitted on the caller thread, not from // Note that protocol messages are transmitted on the caller thread, not from
// any internal libnmdc thread. // any internal libnmdc thread.
func (this *HubConnection) SayRaw(protocolCommand string) error { func (this *HubConnection) SayRaw(protocolCommand string) error {
if this.connValid {
_, err := this.conn.Write([]byte(protocolCommand)) _, err := this.conn.Write([]byte(protocolCommand))
return err return err
} else {
return ErrNotConnected
}
} }
func parseLock(lock []byte) string { func parseLock(lock []byte) string {
@@ -197,14 +217,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
} }
@@ -234,27 +254,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{}
@@ -262,7 +282,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":
@@ -278,31 +298,30 @@ 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
} }
case "$UserCommand":
// TODO
case "$ForceMove": case "$ForceMove":
// TODO this.Hco.Address = HubAddress(commandParts[1])
this.conn.Close() // we'll reconnect onto the new address
// IGNORABLE COMMANDS // IGNORABLE COMMANDS
case "$Supports": case "$Supports":
case "$UserCommand": // TODO $UserCommand 1 1 Group chat\New group chat$<%[mynick]> !groupchat_new&#124;|
case "$UserList": case "$UserList":
case "$OpList": case "$OpList":
case "$HubTopic": case "$HubTopic":
@@ -310,7 +329,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] + "'"})
} }
} }
@@ -325,34 +344,47 @@ func (this *HubConnection) worker() {
// If we're not connected, attempt reconnect // If we're not connected, attempt reconnect
if this.conn == nil { if this.conn == nil {
fullBuffer = "" // clear
if this.Hco.Address.IsSecure() { if this.Hco.Address.IsSecure() {
this.conn, err = tls.Dial("tcp", this.Hco.Address.GetHostOnly(), nil) this.conn, err = tls.Dial("tcp", this.Hco.Address.GetHostOnly(), &tls.Config{
InsecureSkipVerify: this.Hco.SkipVerifyTLS,
})
} else { } else {
this.conn, err = net.Dial("tcp", this.Hco.Address.GetHostOnly()) this.conn, err = net.Dial("tcp", this.Hco.Address.GetHostOnly())
} }
if err == nil { if err != nil {
this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTING} this.State = CONNECTIONSTATE_DISCONNECTED
this.connValid = false
} else {
this.State = CONNECTIONSTATE_CONNECTING
this.connValid = true
this.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTING})
} }
} }
// Read from socket into our local buffer (blocking) // Read from socket into our local buffer (blocking)
if this.conn != nil { if this.connValid {
readBuff := make([]byte, 4096) readBuff := make([]byte, 1024)
this.conn.SetReadDeadline(time.Now().Add(SEND_KEEPALIVE_EVERY))
nbytes, err = this.conn.Read(readBuff) nbytes, err = this.conn.Read(readBuff)
if err != nil && err.(net.Error).Timeout() {
// No data before read deadline
err = nil
// Send KA packet
_, err = this.conn.Write([]byte("|"))
}
if nbytes > 0 { if nbytes > 0 {
fullBuffer += string(readBuff[0:nbytes]) fullBuffer += string(readBuff[0:nbytes])
} }
} }
// Maybe we disconnected
if err != nil {
this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_DISCONNECTED, Message: err.Error()}
this.conn = nil
time.Sleep(30 * time.Second) // Wait before reconnect
continue
}
// Attempt to parse a message block // Attempt to parse a message block
for len(fullBuffer) > 0 { for len(fullBuffer) > 0 {
for len(fullBuffer) > 0 && fullBuffer[0] == '|' { for len(fullBuffer) > 0 && fullBuffer[0] == '|' {
@@ -360,38 +392,66 @@ func (this *HubConnection) worker() {
} }
protocolMessage := rx_protocolMessage.FindString(fullBuffer) protocolMessage := rx_protocolMessage.FindString(fullBuffer)
if len(protocolMessage) > 0 { if len(protocolMessage) > 0 {
this.processProtocolMessage(string(protocolMessage)) this.processProtocolMessage(protocolMessage[:len(protocolMessage)-1])
fullBuffer = fullBuffer[len(protocolMessage):] fullBuffer = fullBuffer[len(protocolMessage):]
} else { } else {
break break
} }
} }
// Maybe we disconnected
// Perform this check *last*, to ensure we've had a final shot at
// clearing out any queued messages
if err != nil {
this.State = CONNECTIONSTATE_DISCONNECTED
this.conn = nil
this.connValid = false
this.processEvent(HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_DISCONNECTED, Message: err.Error()})
time.Sleep(30 * time.Second) // Wait before reconnect
continue
} }
} }
}
func (this *HubConnectionOptions) prepareConnection() *HubConnection {
if this.Self.ClientTag == "" {
this.Self.ClientTag = DEFAULT_CLIENT_TAG
}
hc := HubConnection{
Hco: this,
HubName: DEFAULT_HUB_NAME,
State: CONNECTIONSTATE_DISCONNECTED,
Users: make(map[string]UserInfo),
}
return &hc
}
// Connects to an NMDC server, and spawns a background goroutine to handle // Connects to an NMDC server, and spawns a background goroutine to handle
// protocol messages. Client code should select on all the interface channels. // protocol messages. Client code should select on all the interface channels.
func (this *HubConnectionOptions) Connect() *HubConnection { func (this *HubConnectionOptions) Connect() *HubConnection {
if this.Self.ClientTag == "" {
this.Self.ClientTag = "libnmdc.go"
}
if this.NumEventsToBuffer < 1 { if this.NumEventsToBuffer < 1 {
this.NumEventsToBuffer = 1 this.NumEventsToBuffer = 1
} }
hc := HubConnection{ hc := this.prepareConnection()
Hco: this, hc.OnEvent = make(chan HubEvent, this.NumEventsToBuffer)
HubName: "(unknown)", hc.processEvent = func(ev HubEvent) {
State: CONNECTIONSTATE_DISCONNECTED, hc.OnEvent <- ev
Users: make(map[string]UserInfo),
OnEvent: make(chan HubEvent, this.NumEventsToBuffer),
sentOurHello: false,
} }
go hc.worker() go hc.worker()
return hc
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()
} }

View File

@@ -0,0 +1,38 @@
// +build ignore
// This sample file demonstrates use of the libnmdc.go library. It's excluded
// when building the library package, but you can run it via `go run libnmdc_sample.go`.
package main
import (
"fmt"
"libnmdc"
)
func main() {
opts := libnmdc.HubConnectionOptions{
Address: "127.0.0.1",
Self: libnmdc.UserInfo{Nick: "slowpoke9"},
}
hub := opts.Connect()
for {
event := <-hub.OnEvent
switch event.EventType {
case libnmdc.EVENT_CONNECTION_STATE_CHANGED:
fmt.Printf("Connection -- %s (%s)\n", event.StateChange.Format(), event.Message)
case libnmdc.EVENT_PUBLIC:
fmt.Printf("Message from '%s': '%s'\n", event.Nick, event.Message)
if event.Message == "how are you" {
hub.SayPublic("good thanks!")
}
default:
fmt.Printf("%+v\n", event)
}
}
}

View File

@@ -0,0 +1,46 @@
A logging service for NMDC hubs.
It logs public chat messages to a file, categorised by months. Binaries are provided for Windows/Linux amd64/i386.
Written in golang
Tags: nmdc
=USAGE=
`$nmdc-log-service -Help
Usage of nmdc-log-service:
-Debug
Print additional information on stdout
-Dir string
Output directory (default ".")
-LogConnectionState
Include connection state changes in log (default true)
-Nick string
Nick (default "nmdc-log-service")
-PMResponse string
Message to respond with on PM (default "This is an automated service. For enquiries, please contact an administrator.")
-Password string
Registered nick password
-Server string
Addresses to connect to (comma-separated)
-VerifyTLS
Verify TLS certificates (default true)
`
=CHANGELOG=
2016-04-04 1.0.3
- Enhancement: Upgrade `libnmdc` from `r4` to `r5`
2016-04-03 1.0.2
- Enhancement: Upgrade `libnmdc` from `r3` to `r4`
2016-04-03 1.0.1
- Enhancement: Add `-VerifyTLS` option
- Enhancement: Upgrade `libnmdc` from `r2` to `r3`
- Fix an issue writing log files on Linux
- Fix a cosmetic issue with error message formatting
2016-04-02 1.0.0
- Initial public release

View File

@@ -24,22 +24,22 @@ main() {
fi fi
echo "Building win64..." echo "Building win64..."
GOARCH=amd64 GOOS=windows go build -ldflags -s -o nmdc-log-service.exe GOARCH=amd64 GOOS=windows go build -a -ldflags -s -o nmdc-log-service.exe
7z a -mx9 nmdc-log-service-${version}-win64.7z nmdc-log-service.exe >/dev/null 7z a -mx9 nmdc-log-service-${version}-win64.7z nmdc-log-service.exe >/dev/null
rm ./nmdc-log-service.exe rm ./nmdc-log-service.exe
echo "Building win32..." echo "Building win32..."
GOARCH=386 GOOS=windows go build -ldflags -s -o nmdc-log-service.exe GOARCH=386 GOOS=windows go build -a -ldflags -s -o nmdc-log-service.exe
7z a -mx9 nmdc-log-service-${version}-win32.7z nmdc-log-service.exe >/dev/null 7z a -mx9 nmdc-log-service-${version}-win32.7z nmdc-log-service.exe >/dev/null
rm ./nmdc-log-service.exe rm ./nmdc-log-service.exe
echo "Building linux64..." echo "Building linux64..."
GOARCH=amd64 GOOS=linux go build -ldflags -s -o nmdc-log-service GOARCH=amd64 GOOS=linux go build -a -ldflags -s -o nmdc-log-service
XZ_OPT=-9 tar caf nmdc-log-service-${version}-linux64.tar.xz nmdc-log-service --owner=0 --group=0 XZ_OPT=-9 tar caf nmdc-log-service-${version}-linux64.tar.xz nmdc-log-service --owner=0 --group=0
rm ./nmdc-log-service rm ./nmdc-log-service
echo "Building linux32..." echo "Building linux32..."
GOARCH=386 GOOS=linux go build -ldflags -s -o nmdc-log-service GOARCH=386 GOOS=linux go build -a -ldflags -s -o nmdc-log-service
XZ_OPT=-9 tar caf nmdc-log-service-${version}-linux32.tar.xz nmdc-log-service --owner=0 --group=0 XZ_OPT=-9 tar caf nmdc-log-service-${version}-linux32.tar.xz nmdc-log-service --owner=0 --group=0
rm ./nmdc-log-service rm ./nmdc-log-service

View File

@@ -15,6 +15,7 @@ var BaseDir string = "."
var PMResponse string = "" var PMResponse string = ""
var LogConnectionState bool var LogConnectionState bool
var DebugMode bool var DebugMode bool
var VerifyTLS bool
var CharacterMatcher *regexp.Regexp var CharacterMatcher *regexp.Regexp
func init() { func init() {
@@ -36,7 +37,7 @@ func LogMessage(hub, message string) {
// Produce a timestamp // Produce a timestamp
timeStamp := instant.Format("2006-01-02 15:04:05") timeStamp := instant.Format("2006-01-02 15:04:05")
fh, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE, 0644) fh, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Couldn't open file '%s': %s\n", logFilePath, err.Error()) fmt.Fprintf(os.Stderr, "Couldn't open file '%s': %s\n", logFilePath, err.Error())
return return
@@ -54,6 +55,7 @@ func HubWorker(addr, nick, password string) {
opts := libnmdc.HubConnectionOptions{ opts := libnmdc.HubConnectionOptions{
Address: libnmdc.HubAddress(addr), Address: libnmdc.HubAddress(addr),
SkipVerifyTLS: !VerifyTLS,
Self: libnmdc.UserInfo{Nick: nick}, Self: libnmdc.UserInfo{Nick: nick},
NickPassword: password, NickPassword: password,
} }
@@ -104,18 +106,23 @@ func main() {
flag.BoolVar(&LogConnectionState, "LogConnectionState", true, "Include connection state changes in log") flag.BoolVar(&LogConnectionState, "LogConnectionState", true, "Include connection state changes in log")
flag.StringVar(&PMResponse, "PMResponse", "This is an automated service. For enquiries, please contact an administrator.", "Message to respond with on PM") flag.StringVar(&PMResponse, "PMResponse", "This is an automated service. For enquiries, please contact an administrator.", "Message to respond with on PM")
flag.BoolVar(&DebugMode, "Debug", false, "Print additional information on stdout") flag.BoolVar(&DebugMode, "Debug", false, "Print additional information on stdout")
flag.BoolVar(&VerifyTLS, "VerifyTLS", true, "Verify TLS certificates")
flag.Parse() flag.Parse()
// Assert dir exists // Assert dir exists
dinfo, err := os.Stat(BaseDir) dinfo, err := os.Stat(BaseDir)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "FATAL: %s", err.Error()) fmt.Fprintf(os.Stderr, "FATAL: %s\n", err.Error())
os.Exit(1) os.Exit(1)
} }
if !dinfo.IsDir() { if !dinfo.IsDir() {
fmt.Fprintf(os.Stderr, "FATAL: Path '%s' is not a directory\n", BaseDir) fmt.Fprintf(os.Stderr, "FATAL: Path '%s' is not a directory\n", BaseDir)
} }
if !VerifyTLS {
fmt.Fprintf(os.Stderr, "WARNING: TLS certificates will not be verified!\n")
}
// Launch loggers // Launch loggers
all_hubs := strings.Split(*hubs, ",") all_hubs := strings.Split(*hubs, ",")
launch_ct := 0 launch_ct := 0