123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- package goStrongswanVici
- import (
- "fmt"
- "io"
- "net"
- "sync"
- "time"
- )
- const (
- DefaultReadTimeout = 15 * time.Second
- )
- // This object is not thread safe.
- // if you want concurrent, you need create more clients.
- type ClientConn struct {
- conn net.Conn
- responseChan chan segment
- eventHandlers map[string]func(response map[string]interface{})
- lastError error
- // ReadTimeout specifies a time limit for requests made
- // by this client.
- ReadTimeout time.Duration
- lock sync.RWMutex
- }
- func (c *ClientConn) Close() error {
- c.lock.Lock()
- defer c.lock.Unlock()
- close(c.responseChan)
- c.lastError = io.ErrClosedPipe
- return c.conn.Close()
- }
- func NewClientConn(conn net.Conn) (client *ClientConn) {
- client = &ClientConn{
- conn: conn,
- responseChan: make(chan segment, 2),
- eventHandlers: map[string]func(response map[string]interface{}){},
- ReadTimeout: DefaultReadTimeout,
- }
- go client.readThread()
- return client
- }
- // it dial from unix:///var/run/charon.vici
- func NewClientConnFromDefaultSocket() (client *ClientConn, err error) {
- conn, err := net.Dial("unix", "/var/run/charon.vici")
- if err != nil {
- return
- }
- return NewClientConn(conn), nil
- }
- func (c *ClientConn) Request(apiname string, request map[string]interface{}) (response map[string]interface{}, err error) {
- err = writeSegment(c.conn, segment{
- typ: stCMD_REQUEST,
- name: apiname,
- msg: request,
- })
- if err != nil {
- fmt.Printf("error writing segment \n")
- return
- }
- outMsg := c.readResponse()
- c.lock.RLock()
- err = c.lastError
- if err != nil {
- c.lock.RUnlock()
- return nil, err
- }
- c.lock.RUnlock()
- if outMsg.typ != stCMD_RESPONSE {
- return nil, fmt.Errorf("[%s] response error %d", apiname, outMsg.typ)
- }
- return outMsg.msg, nil
- }
- func (c *ClientConn) readResponse() segment {
- select {
- case outMsg := <-c.responseChan:
- return outMsg
- case <-time.After(c.ReadTimeout):
- if c.lastError == nil {
- c.lock.Lock()
- c.lastError = fmt.Errorf("Timeout waiting for message response")
- c.lock.Unlock()
- }
- return segment{}
- }
- }
- func (c *ClientConn) RegisterEvent(name string, handler func(response map[string]interface{})) (err error) {
- c.lock.Lock()
- if c.eventHandlers[name] != nil {
- c.lock.Unlock()
- return fmt.Errorf("[event %s] register a event twice.", name)
- }
- c.eventHandlers[name] = handler
- err = writeSegment(c.conn, segment{
- typ: stEVENT_REGISTER,
- name: name,
- })
- if err != nil {
- delete(c.eventHandlers, name)
- c.lock.Unlock()
- return
- }
- c.lock.Unlock()
- outMsg := c.readResponse()
- // fmt.Printf("registerEvent %#v\n", outMsg)
- c.lock.Lock()
- lastError := c.lastError
- if lastError != nil {
- delete(c.eventHandlers, name)
- c.lock.Unlock()
- return err
- }
- if outMsg.typ != stEVENT_CONFIRM {
- delete(c.eventHandlers, name)
- c.lock.Unlock()
- return fmt.Errorf("[event %s] response error %d", name, outMsg.typ)
- }
- c.lock.Unlock()
- return nil
- }
- func (c *ClientConn) UnregisterEvent(name string) (err error) {
- err = writeSegment(c.conn, segment{
- typ: stEVENT_UNREGISTER,
- name: name,
- })
- if err != nil {
- return
- }
- outMsg := c.readResponse()
- // fmt.Printf("UnregisterEvent %#v\n", outMsg)
- c.lock.Lock()
- if c.lastError != nil {
- c.lock.Unlock()
- return c.lastError
- }
- c.lock.Unlock()
- if outMsg.typ != stEVENT_CONFIRM {
- return fmt.Errorf("[event %s] response error %d", name, outMsg.typ)
- }
- c.lock.Lock()
- delete(c.eventHandlers, name)
- c.lock.Unlock()
- return nil
- }
- func (c *ClientConn) readThread() {
- for {
- outMsg, err := readSegment(c.conn)
- if err != nil {
- c.lock.Lock()
- c.lastError = err
- c.lock.Unlock()
- return
- }
- switch outMsg.typ {
- case stCMD_RESPONSE, stEVENT_CONFIRM:
- c.responseChan <- outMsg
- case stEVENT:
- c.lock.Lock()
- handler := c.eventHandlers[outMsg.name]
- c.lock.Unlock()
- if handler != nil {
- handler(outMsg.msg)
- }
- default:
- c.lock.Lock()
- c.lastError = fmt.Errorf("[Client.readThread] unknow msg type %d", outMsg.typ)
- c.lock.Unlock()
- return
- }
- }
- }
|