134 lines
2.6 KiB
Go
134 lines
2.6 KiB
Go
package station
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Close releases the log file. It is safe to call more than once.
|
|
func (s *Station) Close() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.closeLogLocked()
|
|
}
|
|
|
|
func (s *Station) openLog() {
|
|
f, err := os.OpenFile(s.logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600)
|
|
if err != nil {
|
|
s.logNotice = "Cannot write " + s.logPath
|
|
if s.state.Talker == "" {
|
|
s.state.Detail = s.logNotice
|
|
}
|
|
return
|
|
}
|
|
s.logFile = f
|
|
}
|
|
|
|
func (s *Station) closeLogLocked() {
|
|
if s.logFile != nil {
|
|
s.logFile.Close()
|
|
s.logFile = nil
|
|
}
|
|
}
|
|
|
|
func (s *Station) writeLog(ts time.Time, msg string) {
|
|
if s.logFile == nil {
|
|
return
|
|
}
|
|
line := ts.Format(time.RFC3339) + " " + msg + "\n"
|
|
if _, err := s.logFile.Write([]byte(line)); err != nil {
|
|
s.closeLogLocked()
|
|
if s.logNotice == "" {
|
|
s.logNotice = "Cannot write " + s.logPath
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Station) noteTransmitLocked() {
|
|
s.noteTransmitAt(s.clock.Now())
|
|
}
|
|
|
|
func (s *Station) noteTransmitAt(now time.Time) {
|
|
tx := s.transmitting()
|
|
if tx && !s.sending {
|
|
s.sending = true
|
|
s.sendStart = now
|
|
return
|
|
}
|
|
if !tx && s.sending {
|
|
start := s.sendStart
|
|
s.sending = false
|
|
s.writeLog(start, fmt.Sprintf("sending for %d seconds.", wholeSeconds(start, now)))
|
|
}
|
|
}
|
|
|
|
func (s *Station) closeTalkerLocked(now time.Time) {
|
|
if s.talkCall == "" {
|
|
return
|
|
}
|
|
call := s.talkCall
|
|
start := s.talkStart
|
|
s.talkCall = ""
|
|
s.writeLog(start, fmt.Sprintf("%s talked for %d seconds.", call, wholeSeconds(start, now)))
|
|
}
|
|
|
|
func (s *Station) noteDownLocked(now time.Time, dial bool) {
|
|
s.closeTalkerLocked(now)
|
|
s.state.Connection = "Disconnected"
|
|
s.remoteTalker = ""
|
|
s.roomBusy = false
|
|
s.noteTransmitAt(now)
|
|
switch {
|
|
case s.up:
|
|
s.up = false
|
|
s.outage = true
|
|
s.writeLog(now, "disconnected")
|
|
case dial && !s.outage:
|
|
s.outage = true
|
|
s.writeLog(now, "disconnected")
|
|
}
|
|
s.publish()
|
|
}
|
|
|
|
func (s *Station) endFatal(msg string, log bool) {
|
|
s.endFatalCause(msg, nil, log)
|
|
}
|
|
|
|
func (s *Station) endFatalCause(msg string, cause error, log bool) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.fatal != "" {
|
|
return
|
|
}
|
|
now := s.clock.Now()
|
|
s.closeTalkerLocked(now)
|
|
s.fatal = msg
|
|
s.remoteTalker = ""
|
|
s.roomBusy = false
|
|
s.noteTransmitAt(now)
|
|
if log {
|
|
s.up = false
|
|
s.outage = true
|
|
line := oneLine(msg)
|
|
if cause != nil {
|
|
line += ": " + oneLine(cause.Error())
|
|
}
|
|
s.writeLog(now, line)
|
|
}
|
|
s.publish()
|
|
}
|
|
|
|
func wholeSeconds(start, end time.Time) int {
|
|
d := end.Sub(start)
|
|
if d <= 0 {
|
|
return 0
|
|
}
|
|
return int(d / time.Second)
|
|
}
|
|
|
|
func oneLine(msg string) string {
|
|
return strings.NewReplacer("\r\n", " ", "\n", " ", "\r", " ").Replace(msg)
|
|
}
|