Advertisement
Guest User

rrrr

a guest
Oct 24th, 2014
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.93 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. "net"
  8. "gopkg.in/qml.v0"
  9. "os"
  10. "strings"
  11. "sync"
  12. )
  13.  
  14. const PORT = ":1500"
  15.  
  16. var (
  17. output chan string = make(chan string) //channel waitin on the user to type something
  18. listIPs map[string]string = make(map[string]string)//list of users IPS connected to me
  19. listConnections map[string]net.Conn = make(map[string]net.Conn)//list of users connections connected to me
  20. myName string //name of the client
  21. testing bool = true
  22. ctrl Control
  23. mutex = new(sync.Mutex)
  24. )
  25.  
  26. type Control struct {
  27. Root qml.Object
  28. convstring string
  29. userlist string
  30. inputString string
  31. }
  32.  
  33. //message sent out to the server
  34. type Message struct {
  35. Kind string //type of message ("CONNECT","PRIVATE","PUBLIC","DISCONNECT","ADD")
  36. Username string //my username
  37. IP string //Ip address of my computer
  38. MSG string //message
  39. Usernames []string //usernames of people connected
  40. IPs []string //IP addresses of all the users connected
  41. }
  42.  
  43. //start the connection, introduces the user to the chat and creates graphical interface.
  44. func main() {
  45. //adding myself to the list
  46. myName= os.Args[2]
  47.  
  48. //starting graphics
  49. qml.Init(nil)
  50. engine := qml.NewEngine()
  51. ctrl = Control{convstring: ""}
  52. ctrl.convstring = ""
  53. context := engine.Context()
  54. context.SetVar("ctrl", &ctrl)
  55. component, err := engine.LoadFile("chat.qml")
  56. if err != nil {
  57. fmt.Println("no file to load for ui")
  58. fmt.Println(err.Error())
  59. os.Exit(0)
  60. }
  61.  
  62. win := component.CreateWindow(nil)
  63. ctrl.Root = win.Root()
  64.  
  65. win.Show() //show window
  66. ctrl.updateText("Hello "+myName+".\nFor private messages, type the message followed by * and the name of the receiver.\n To leave the conversation type disconnect")
  67.  
  68. go server()//starting server
  69. if os.Args[1]!="127.0.0.1"{go introduceMyself(os.Args[1])} //connect to the first peer
  70. go userInput()
  71.  
  72. win.Wait()
  73. closing:=createMessage("DISCONNECT",myName,getMyIp(),"",make([]string,0),make([]string,0))
  74. closing.send()
  75. }
  76.  
  77. //part of the peer that acts like a server
  78.  
  79. //waits for possible peers to connect
  80. func server(){
  81. if testing {log.Println("server")}
  82. tcpAddr, err := net.ResolveTCPAddr("tcp4", PORT)
  83. checkError(err)
  84. listener, err := net.ListenTCP("tcp", tcpAddr)
  85. checkError(err)
  86. for {
  87. conn, err := listener.Accept()
  88. if err != nil {
  89. continue
  90. }
  91.  
  92. go receive(conn)
  93. }
  94. }
  95.  
  96. //receives message from peer
  97. func receive(conn net.Conn){
  98. if testing {log.Println("receive")}
  99. defer conn.Close()
  100. dec:=json.NewDecoder(conn)
  101. msg:= new(Message)
  102. for {
  103. if err := dec.Decode(msg);err != nil {
  104. return
  105. }
  106. switch msg.Kind{
  107. case "CONNECT":
  108. if testing {log.Println("Kind = CONNECT")}
  109. if !handleConnect(*msg, conn){return}
  110. case "PRIVATE":
  111. if testing {log.Println("Kind = PRIVATE")}
  112. ctrl.updateText("(private) from "+msg.Username+": "+msg.MSG)
  113. case "PUBLIC":
  114. if testing {log.Println("Kind = PUBLIC")}
  115. ctrl.updateText(msg.Username+": "+msg.MSG)
  116. case "DISCONNECT":
  117. if testing {log.Println("Kind = DISCONNECT")}
  118. disconnect(*msg)
  119. return
  120. case "HEARTBEAT"://ask about it in the morning
  121. log.Println("HEARTBEAT")
  122. case "LIST":
  123. if testing {log.Println("Kind = LIST")}
  124. connectToPeers(*msg)
  125. return
  126. case "ADD":
  127. if testing {log.Println("Kind = ADD")}
  128. addPeer(*msg)
  129. }
  130. }
  131. }
  132.  
  133. //introduces peer to the chat
  134. func introduceMyself(IP string){
  135. if testing {log.Println("introduceMyself")}
  136. conn:=createConnection(IP)
  137. enc:= json.NewEncoder(conn)
  138. introMessage:= createMessage("CONNECT", myName , getMyIp(), "", make([]string, 0), make([]string, 0))
  139. enc.Encode(introMessage)
  140. go receive(conn)
  141. }
  142.  
  143. //handle a connection with a new peer
  144. func handleConnect(msg Message, conn net.Conn) bool{
  145. if testing {log.Println("handleConnect")}
  146. Users,IPs:=getFromMap(listIPs)
  147. Users = append(Users, myName) //add my name to the list
  148. IPs = append(IPs, getMyIp()) //add my ip to the list
  149. response:=createMessage("LIST","","","",Users,IPs)
  150. if alreadyAUser(msg.Username){
  151. response.MSG="Username already taken, choose another one that is not in the list"
  152. response.send()
  153. return false
  154. }
  155. listIPs[msg.Username]=msg.IP
  156. listConnections[msg.Username]=conn
  157. log.Println(listConnections)
  158. response.sendPrivate(msg.Username)
  159. return true
  160. }
  161.  
  162. //connects with everyone in the chat. The message passed in contains a list of users and ips
  163. func connectToPeers(msg Message) {
  164. for index, ip := range msg.IPs {
  165. conn:=createConnection(ip)
  166. listIPs[msg.Usernames[index]]=ip
  167. listConnections[msg.Usernames[index]]=conn
  168. }
  169. users,_:=getFromMap(listIPs)
  170. ctrl.updateList(users)
  171. addMessage := createMessage("ADD", myName, getMyIp(), "", make([]string, 0), make([]string, 0))
  172. addMessage.send()
  173. }
  174.  
  175. //adds a peer to everyone list
  176. func addPeer(msg Message){
  177. listIPs[msg.Username]=msg.IP
  178. conn:=createConnection(msg.IP)
  179. listConnections[msg.Username]=conn
  180. userNames,_:=getFromMap(listIPs)
  181. ctrl.updateList(userNames)
  182. ctrl.updateText(msg.Username+" just joined the chat")
  183. }
  184.  
  185. //sends message to all peers
  186. func (msg *Message) send(){
  187. if testing {log.Println("send")}
  188. if testing {log.Println(listConnections)}
  189. for _,peerConnection := range listConnections{
  190. enc:=json.NewEncoder(peerConnection)
  191. enc.Encode(msg)
  192. }
  193. ctrl.updateText(myName+": "+msg.MSG)
  194. }
  195.  
  196. //sends message to a peer
  197. func (msg *Message) sendPrivate(receiver string){
  198. if testing {log.Println("sendPrivate")}
  199. if alreadyAUser(receiver){
  200. peerConnection:=listConnections[receiver]
  201. enc:=json.NewEncoder(peerConnection)
  202. enc.Encode(msg)
  203. ctrl.updateText("(private) from "+myName+": "+msg.MSG)
  204. }else{
  205. ctrl.updateText(receiver+" is not a real user")
  206. }
  207. }
  208.  
  209.  
  210. //disconnect user by deleting him/her from list
  211. func disconnect(msg Message){
  212. delete(listIPs, msg.Username)
  213. delete(listConnections, msg.Username)
  214. newUserList, _ := getFromMap(listIPs)
  215. ctrl.updateList(newUserList)
  216. ctrl.updateText(msg.Username + " left the chat")
  217. }
  218.  
  219. func getFromMap(mappa map[string]string) ([]string, []string){
  220. var keys []string
  221. var values []string
  222.  
  223. for key,value := range mappa{
  224. keys = append(keys,key)
  225. values = append(values,value)
  226. }
  227. return keys,values
  228. }
  229.  
  230. //creates a new connection, given the IP address, and returns it
  231. func createConnection(IP string) (conn net.Conn){
  232. service:= IP+PORT
  233. tcpAddr, err := net.ResolveTCPAddr("tcp", service)
  234. handleErr(err)
  235. conn, err = net.DialTCP("tcp", nil, tcpAddr)
  236. handleErr(err)
  237. return
  238. }
  239.  
  240. func getMyIp() (IP string){
  241. name, err := os.Hostname()
  242. handleErr(err)
  243. addr, err := net.ResolveIPAddr("ip", name)
  244. handleErr(err)
  245. IP = addr.String()
  246. return
  247. }
  248.  
  249. func createMessage(Kind string, Username string, IP string, MSG string, Usernames []string, IPs []string) (msg *Message) {
  250. msg = new(Message)
  251. msg.Kind = Kind
  252. msg.Username = Username
  253. msg.IP = IP
  254. msg.MSG = MSG
  255. msg.Usernames = Usernames
  256. msg.IPs = IPs
  257. return
  258. }
  259.  
  260. //sends message to the server
  261. func userInput(){
  262. if testing {log.Println("userInput")}
  263. msg:=new(Message)
  264. for {
  265. message:= <-output
  266. whatever:=strings.Split(message,"*")
  267. if message=="disconnect"{
  268. msg=createMessage("DISCONNECT",myName,"","", make([]string, 0), make([]string, 0))
  269. msg.send()
  270. break
  271. } else if len(whatever)>1 {
  272. msg=createMessage("PRIVATE",myName,"",whatever[0], make([]string, 0), make([]string, 0))
  273. msg.sendPrivate(whatever[1])
  274. } else {
  275. msg=createMessage("PUBLIC",myName,"",whatever[0], make([]string, 0), make([]string, 0))
  276. msg.send()
  277. }
  278. }
  279. os.Exit(1)
  280. }
  281.  
  282. func handleErr(err error) {
  283. if err != nil {
  284. log.Println("No one in the chat yet")
  285. }
  286. }
  287.  
  288. func checkError(err error) {
  289. if err != nil {
  290. fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
  291. os.Exit(1)
  292. }
  293. }
  294.  
  295. //checks to see if a userName is already in the list
  296. func alreadyAUser(user string) bool {
  297. for userName,_:= range listIPs {
  298. if userName == user {return true}
  299. }
  300. return false
  301. }
  302.  
  303.  
  304. //Graphics methods
  305.  
  306. func (ctrl *Control) TextEntered(text qml.Object) {
  307. //this method is called whenever a return key is typed in the text entry field. The qml object calls this function
  308. ctrl.inputString = text.String("text") //the ctrl's inputString field holds the message
  309. //you will want to send it to the server
  310. //but for now just send it back to the conv field
  311. //ctrl.updateText(ctrl.inputString)
  312. output <- ctrl.inputString
  313.  
  314. }
  315.  
  316. func (ctrl *Control) updateText(toAdd string) {
  317. //call this method whenever you want to add text to the qml object's conv field
  318. ctrl.convstring = ctrl.convstring + toAdd + "\n" //also keep track of everything in that field
  319. ctrl.Root.ObjectByName("conv").Set("text", ctrl.convstring)
  320. qml.Changed(ctrl, &ctrl.convstring)
  321. }
  322.  
  323. func (ctrl *Control) updateList(list []string) {
  324. ctrl.userlist = ""
  325. for _, user := range list {
  326. ctrl.userlist += user + "\n"
  327. }
  328. ctrl.Root.ObjectByName("userlist").Set("text", ctrl.userlist)
  329. qml.Changed(ctrl, &ctrl.userlist)
  330. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement