148 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package up
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"os/signal"
 | |
| 
 | |
| 	"github.com/gorilla/websocket"
 | |
| )
 | |
| 
 | |
| // Worker handles a functional service
 | |
| type Worker struct {
 | |
| 	conn   *websocket.Conn
 | |
| 	ch     chan<- bool
 | |
| 	src    string
 | |
| 	lang   string
 | |
| 	logger *Logger
 | |
| 	dead   bool
 | |
| }
 | |
| 
 | |
| // NewWorker creates and returns a new worker
 | |
| func NewWorker(src, lang string, conn *websocket.Conn, ch chan<- bool) *Worker {
 | |
| 	worker := &Worker{
 | |
| 		src:    src,
 | |
| 		lang:   lang,
 | |
| 		conn:   conn,
 | |
| 		ch:     ch,
 | |
| 		logger: NewLogger("[" + src + "]"),
 | |
| 	}
 | |
| 	worker.conn.SetCloseHandler(worker.closeHandler)
 | |
| 	return worker
 | |
| }
 | |
| 
 | |
| func (worker *Worker) checkErr(err error) bool {
 | |
| 	if err != nil {
 | |
| 		worker.logger.Err(err)
 | |
| 		if !websocket.IsCloseError(err, 1000) {
 | |
| 			worker.ch <- false
 | |
| 		}
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (worker *Worker) closeHandler(
 | |
| 	code int,
 | |
| 	msg string,
 | |
| ) error {
 | |
| 	worker.dead = true
 | |
| 	if msg == "0" {
 | |
| 		worker.ch <- true
 | |
| 		worker.logger.Log(msg)
 | |
| 	} else {
 | |
| 		worker.ch <- false
 | |
| 		worker.logger.Err(msg)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Work starts and handles a function from Worker's information
 | |
| func (worker *Worker) Work() {
 | |
| 	if worker.dead {
 | |
| 		return
 | |
| 	}
 | |
| 	logger := worker.logger
 | |
| 	conn := worker.conn
 | |
| 	logger.Log("Deploying...")
 | |
| 	// Open function source file
 | |
| 	file, err := os.Open(worker.src)
 | |
| 	if worker.checkErr(err) {
 | |
| 		return
 | |
| 	}
 | |
| 	defer file.Close()
 | |
| 	// Send source language type
 | |
| 	err = conn.WriteMessage(
 | |
| 		websocket.TextMessage,
 | |
| 		[]byte(worker.lang),
 | |
| 	)
 | |
| 	if worker.checkErr(err) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Get websocket connection writer
 | |
| 	writer, err := conn.NextWriter(
 | |
| 		websocket.TextMessage,
 | |
| 	)
 | |
| 	if worker.checkErr(err) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Send function source file
 | |
| 	bytesSent, err := io.Copy(
 | |
| 		writer,
 | |
| 		file,
 | |
| 	)
 | |
| 	if worker.checkErr(err) {
 | |
| 		return
 | |
| 	}
 | |
| 	logger.Log(
 | |
| 		fmt.Sprintf(
 | |
| 			"Sent bytes: %d",
 | |
| 			bytesSent,
 | |
| 		))
 | |
| 	err = writer.Close()
 | |
| 	if worker.checkErr(err) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	interrupt := make(chan os.Signal, 2)
 | |
| 	signal.Notify(interrupt, os.Interrupt, os.Kill)
 | |
| 
 | |
| 	errChan := make(chan error)
 | |
| 	msgChan := make(chan string)
 | |
| 	readReply := func(
 | |
| 		c *websocket.Conn,
 | |
| 		msgCh chan<- string,
 | |
| 		errCh chan<- error,
 | |
| 	) {
 | |
| 		_, msg, err := c.ReadMessage()
 | |
| 		if err != nil {
 | |
| 			errCh <- err
 | |
| 			return
 | |
| 		}
 | |
| 		msgCh <- string(msg)
 | |
| 	}
 | |
| 	go readReply(conn, msgChan, errChan)
 | |
| 
 | |
| 	// Wait for deploy done
 | |
| 	for {
 | |
| 		select {
 | |
| 		case <-interrupt:
 | |
| 			closeMsg := websocket.FormatCloseMessage(1000, "1")
 | |
| 			conn.WriteMessage(websocket.CloseMessage, closeMsg)
 | |
| 		case newMsg := <-msgChan:
 | |
| 			logger.Log(newMsg)
 | |
| 			if worker.dead {
 | |
| 				return
 | |
| 			}
 | |
| 			go readReply(conn, msgChan, errChan)
 | |
| 		case newErr := <-errChan:
 | |
| 			if worker.checkErr(newErr) {
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
