-
Notifications
You must be signed in to change notification settings - Fork 5
/
chat.go
195 lines (165 loc) · 5.29 KB
/
chat.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package main
/*
chat v.0.9.7 Dec 5 2019
a HNET (BITNET) chat daemon, starts and listens for input to a FIFO pipe
defined in pipeFile
invoke with:
chat &
(c) 2019 by moshix
Program source is under Apache license */
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"time"
)
// change this to suit your needs
const pipeFile = "/root/chat/chat.pipe"
const sendCommand = "/usr/local/bin/send"
var msgcount int64 // total messages sent, used by /STATS command
var totaluser int64 // total users logged in, used by /STATS command
//var prevmsg1 string // last message for loop detector
//var prevmsg2 string // before last message
type users struct {
useratnode string //user@node
lastmessage string //what was the last message setn by this user
timer int //what is this users desired logoff timer
lastactivity int64 //updated every time this user does something
}
var table map[string]users // map of structs of all logged on users
// function to prune old inactive users every minute
func purgeinactive() {
for range time.Tick(time.Minute * 1) {
thirtyMinutesAgo := time.Now().Add(time.Duration(-120) * time.Minute).Unix()
for username, userStruct := range table {
if userStruct.lastactivity < thirtyMinutesAgo {
log.Printf("Deleting inactive user '%s'", username)
delete(table, username)
}
}
}
}
func main() {
table = make(map[string]users)
fmt.Println("HNET chat server started....")
file, err := os.OpenFile(pipeFile, os.O_CREATE, os.ModeNamedPipe)
if err != nil {
log.Fatal("Open named pipe file error:", err)
} else {
fmt.Print("FIFO pipe successfully opened and now listening\n")
}
go purgeinactive() // start inactive user purger now
// here is the pipe listening to all incoming messages
reader := bufio.NewReader(file)
for {
line, err := reader.ReadBytes('\n')
if err == nil {
readcommand(strings.TrimSuffix(string(line), "\n")) //pass incoming line to messager parser
}
time.Sleep(400 * time.Millisecond) // wait a bit to avoid excessive CPU usage
}
}
func send(arg ...string) {
cmd := exec.Command(sendCommand, arg...)
if _, err := cmd.CombinedOutput(); err != nil {
log.Fatalf("send failed with %s\n", err)
}
msgcount++
}
func readcommand(fifoline string) {
var fifouser string
var fifomsg string
var upperfifomsg string
var upperfifouser string
s := strings.Split(fifoline, "}") //split this message into sender and msg content
fifouser = s[0]
fifomsg = s[1] //this is the payload part of the incoming msg
upperfifomsg = strings.ToUpper(fifomsg) //make upper case for commands processing
upperfifouser = strings.ToUpper(fifouser) //make user upper case
fmt.Printf("'%s' '%s'\n", upperfifouser, fifomsg)
//at this point we have the user at node and the payload in fifomsg/upperfifomsg
//now we start some very simple processing
//---------------------------------------------------------------------------------
// /HELP sends to the user a help menu with ossibilities
// /WHO sends a list of logged on (recently) users
// /LOGON logs the user on and adds her to the list
// /LOGOFF logs the user off and removes him from thelist
// //STATS sends usage statistics
//---------------------------------------------------------------------------------
switch upperfifomsg {
case "/HELP":
// fmt.Println("This is the help case")
break
case "/WHO":
// fmt.Println("This is the WHO case")
senduserlist(upperfifouser)
break
case "/STATS":
// fmt.Println("This is the STATS case")
sendstats(upperfifouser)
break
case "/LOGON":
// fmt.Println("This is the LOGON case")
adduser(upperfifouser)
break
case "/LOGOFF":
// fmt.Println("This is the LOGOFF case")
deluser(upperfifouser)
break
default:
// must be a regular chat message
if _, ok := table[upperfifouser]; ok {
table[upperfifouser] = users{
lastactivity: time.Now().Unix(),
}
broacastmsg(upperfifouser, fifouser, fifomsg)
} else {
send(upperfifouser, "You are not logged on currently to RELAY chat")
}
}
}
func senduserlist(upperfifouser string) {
for user := range table {
send(upperfifouser, "Online last 120 min: ", user)
}
}
func sendstats(user string) {
s := strconv.FormatInt(msgcount, 10)
t := strconv.FormatInt(totaluser, 10)
send(user, " Total messages: ", s, " Total users:", t)
}
func adduser(user string) {
table[user] = users{
lastactivity: time.Now().Unix(),
}
send(user, " Welcome to RELAY CHAT v0.9.6")
totaluser++
}
func deluser(user string) {
delete(table, user)
send(user, " Goodbye from RELAY CHAT v0.9.6")
}
func broacastmsg(upperfifouser string, fifouser string, fifomsg string) {
// remove users inactive for 120 minutes
thirtyMinutesAgo := time.Now().Add(time.Duration(-120) * time.Minute).Unix()
for username, userStruct := range table {
if userStruct.lastactivity < thirtyMinutesAgo {
log.Printf("Deleting inactive user '%s'", username)
delete(table, username)
}
}
loopmsg := fifomsg[0:3] //this is the begignning of a user who is not logged on anymore
//Looping messages begin with DMT, filter those
if loopmsg == "DMT" {
delete(table, upperfifouser)
}
for upperfifouser := range table {
if _, ok := table[upperfifouser]; ok {
send(upperfifouser, "> ", fifouser, fifomsg)
}
}
}