kiosk current files
[svn42.git] / go / door_daemon / unix_socket_server.go
1 package main
2 import "fmt"
3 import "net"
4 import "bufio"
5 import "strings"
6 import "os"
7 import "io"
8 import "svn.spreadspace.org/realraum/go.svn/termios"
9 import "flag"
10 import "regexp"
11 import "sync"
12 import "time"
13
14 var lock sync.RWMutex
15
16 type DoorConnection struct {
17   rw * bufio.ReadWriter
18   c net.Conn
19   wchan chan string
20 }
21
22 var DoorConnectionMap = map[uint]DoorConnection {
23 }
24
25 var cmdHandler = map[string]func([]string,string,*bufio.ReadWriter ) {
26   "test":handleCmdTest,
27   "open":handleCmdController,
28   "close":handleCmdController,
29   "toggle":handleCmdController,
30 }
31
32
33 func readLineSafe(rw *bufio.Reader) (string, error) {
34   wasPrefix:=false
35   var line string
36   for isPrefix:=true;isPrefix; {
37     var lineBuf []byte 
38     var err error
39     lineBuf,isPrefix,err = rw.ReadLine()
40     if err != nil {
41         return "",err
42     }
43     if isPrefix {
44       wasPrefix=true
45     } else {
46       line=string(lineBuf)
47     }
48   }
49   if wasPrefix {
50       fmt.Println("line too long")
51       //fmt.Fprintf(rw,"line too long\n")
52       //rw.Flush()
53       return "",nil
54   }
55   reg := regexp.MustCompile("\r")
56   safe := reg.ReplaceAllString(line, "")
57   return safe,nil
58 }
59
60 func connToReadWriter(c io.Reader,cw io.Writer) (*bufio.ReadWriter) {
61     client_r := bufio.NewReaderSize(c,1024)
62     client_w := bufio.NewWriterSize(cw,1024)
63     return bufio.NewReadWriter(client_r,client_w)
64 }
65
66 func handleConnection(c net.Conn, client * bufio.ReadWriter, connID uint) () {
67     fmt.Println("new connection")
68     defer func () {
69      lock.Lock()
70      delete(DoorConnectionMap,connID)
71      lock.Unlock()
72     }()
73     for {
74          line,err:=readLineSafe(bufio.NewReader(client))
75          if err != nil {
76           if err.Error() != "EOF" {
77             fmt.Printf("Error: readLineSafe returned %v\n",err.Error())
78           } else {
79             fmt.Printf("Connection closed by remote host\n");
80           }
81           c.Close()
82           return
83          }
84          if line == "" {
85            continue
86          }
87          fmt.Printf("Received: %v\n", line)
88          tokens:=strings.Fields(line)
89          remainStr:=strings.Join(tokens[1:]," ")
90          handleCmd(tokens,remainStr,client)
91     }
92 }
93
94 func handleCmd(tokens []string, remainStr string,client * bufio.ReadWriter) {
95   cmd:=tokens[0]
96   func_ptr,present := cmdHandler[cmd]
97   if present {
98     func_ptr(tokens, remainStr,client)
99   } else {
100     fmt.Printf("Error: unknown Cmd: %v\n", cmd)
101   }
102 }
103
104 func handleCmdTest(tokens []string, remainStr string, client * bufio.ReadWriter) {
105   //cmd:=tokens[0]
106   fmt.Printf("Test: %v\n", remainStr)
107 }
108
109 func handleCmdController(tokens []string, remainStr string, client * bufio.ReadWriter) {
110   cmd:=tokens[0]
111   s_r:=strings.NewReader(cmd)
112   char := make([]byte,1)
113   s_r.Read(char)
114   fmt.Println(string(char))
115 }
116
117
118 func openTTY(name string) *os.File {
119   file, err := os.OpenFile(name,os.O_RDWR  ,0600) // For read access.
120   if err != nil {
121     fmt.Println(err.Error())
122   }
123   termios.Ttyfd(file.Fd())
124   termios.SetRaw()
125   return file 
126 }
127 func usage() {
128     fmt.Fprintf(os.Stderr, "usage: myprog [inputfile]\n")
129     flag.PrintDefaults()
130     os.Exit(2)
131 }
132
133 func SerialWriter(c chan string, serial * os.File ) {
134   for {
135     serial.WriteString(<-c)
136     serial.Sync()
137   }
138 }
139
140 func SerialReader(c chan string , serial * bufio.Reader) {
141   for {
142     s,err := readLineSafe(serial)
143     if (s=="") {
144      continue
145     }
146     if (err!=nil) {
147      fmt.Printf("Error in read from serial: %v\n",err.Error())
148      os.Exit(1)
149     }
150     //fmt.Printf("Serial: Read %v\n",s);
151     c<-s
152   }
153 }
154
155 func openSerial(filename string) (chan string,chan string) {
156   serial:=openTTY(filename)
157   in:=make(chan string)
158   out:=make(chan string)
159   go SerialWriter(out,serial)
160   go SerialReader(in,bufio.NewReaderSize(serial,128))
161   return in,out
162 }
163
164 func SerialHandler(serial_i chan string) {
165   for {
166     line:=<-serial_i
167     fmt.Printf("Serial Read: %s\n",line)
168     lock.RLock()
169     for _, v := range DoorConnectionMap{
170       select {
171         case v.wchan<-line:
172
173         case <-time.After(2):
174
175       }
176     }
177     lock.RUnlock()
178   }
179 }
180
181 func chanWriter(c chan string, w io.Writer) {
182   for {
183     line := <-c
184      w.Write([]byte(line))
185      w.Write([]byte("\n"))
186   }
187 }
188 func main() {
189 //    lock = make(sync.RWMutex)
190     flag.Usage = usage
191     flag.Parse()
192
193     args := flag.Args()
194     if len(args) < 1 {
195         fmt.Println("Input file is missing.");
196         os.Exit(1);
197     }
198   serial_i,serial_o:=openSerial(args[0]) 
199   go SerialHandler(serial_i)
200   serial_o<-"f"
201
202   ln, err := net.Listen("unix", "/tmp/test.sock")
203   if err != nil {
204     fmt.Printf("Error: %s\n",err.Error())
205     return
206   }
207   fmt.Printf("Listener started\n")
208
209   var connectionID uint =0
210   for {
211     conn, err := ln.Accept()
212     if err != nil {
213       // handle error
214      continue
215     }
216    client:=connToReadWriter(conn,conn)
217    connectionID++
218    writeChan := make(chan string)
219    lock.Lock()
220    DoorConnectionMap[connectionID]= DoorConnection{ rw:client,c:conn, wchan:writeChan }
221    lock.Unlock()
222    go handleConnection(conn,client,connectionID)
223    go chanWriter(writeChan,conn)
224   }
225 }