Esempio n. 1
0
func TestHttpServer(t *testing.T) {
	bytes, err := ioutil.ReadFile("../../test/stories/binder_stories.js")
	if err != nil {
		t.Errorf("Read file error: %v", err)
		return
	}

	var scont binderStoriesContainer
	if err := json.Unmarshal(bytes, &scont); err != nil {
		t.Errorf("Story parse error: %v", err)
		return
	}

	logger, stats := loggerAndStats()
	auth, storage := authAndStore(logger, stats)

	curator, err := curator.New(curator.NewConfig(), logger, stats, auth, storage)
	if err != nil {
		t.Errorf("Curator error: %v", err)
	}

	ts := httptest.NewServer(websocket.Handler(
		WebsocketHandler(curator, time.Second, logger, stats),
	))
	defer ts.Close()

	time.Sleep(50 * time.Millisecond)

	wsURL := strings.Replace(ts.URL, "http", "ws", 1)

	origin := "http://127.0.0.1/"
	url := wsURL + "/leaps/socket"

	for _, story := range scont.Stories {

		ws, err := websocket.Dial(url, "", origin)
		if err != nil {
			t.Errorf("client connect error: %v", err)
			return
		}

		websocket.JSON.Send(ws, leapHTTPClientMessage{
			Command: "create",
			UserID:  "test",
			Document: &store.Document{
				Content: story.Content,
			},
		})

		var initResponse leapHTTPServerMessage
		if err := websocket.JSON.Receive(ws, &initResponse); err != nil {
			t.Errorf("Init receive error: %v", err)
			return
		}

		switch initResponse.Type {
		case "document":
		case "error":
			t.Errorf("Server returned error: %v", initResponse.Error)
			return
		default:
			t.Errorf("unexpected message type from server init: %v", initResponse.Type)
			return
		}

		feeds := make(chan text.OTransform)

		wg := sync.WaitGroup{}
		wg.Add(10)

		go senderClient(initResponse.Document.ID, url, feeds, t)
		for j := 0; j < 10; j++ {
			go goodStoryClient(initResponse.Document.ID, url, &story, &wg, t)
		}

		time.Sleep(50 * time.Millisecond)

		for j := 0; j < len(story.Transforms); j++ {
			feeds <- story.Transforms[j]
		}

		wg.Wait()
	}

	curator.Close()
}
Esempio n. 2
0
func main() {
	var (
		err       error
		closeChan = make(chan bool)
	)

	flag.Usage = func() {
		fmt.Println(`Usage: leaps [flags...] [path/to/share]

If a path is not specified the current directory is shared instead.
`)
		flag.PrintDefaults()
	}

	flag.Parse()

	targetPath := "."
	if flag.NArg() == 1 {
		targetPath = flag.Arg(0)
	}

	// Logging and metrics aggregation
	logConf := log.NewLoggerConfig()
	logConf.Prefix = "leaps"
	logConf.LogLevel = *logLevel

	logger := log.NewLogger(os.Stdout, logConf)

	statConf := metrics.NewConfig()
	statConf.Prefix = "leaps"

	stats, err := metrics.New(statConf)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("Metrics init error: %v\n", err))
		return
	}
	defer stats.Close()

	logger.Infoln("Launching a leaps instance, use CTRL+C to close.")

	// Document storage engine
	docStore, err := store.NewFile(".")
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("Document store error: %v\n", err))
		return
	}

	// Authenticator
	storeConf := acl.NewFileExistsConfig()
	storeConf.Path = targetPath
	storeConf.ShowHidden = *showHidden

	authenticator := acl.NewFileExists(storeConf, logger)

	// Curator of documents
	curatorConf := curator.NewConfig()
	curator, err := curator.New(curatorConf, logger, stats, authenticator, docStore)
	if err != nil {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("Curator error: %v\n", err))
		return
	}
	defer curator.Close()

	handle("/endpoints", "Lists all available endpoints (including this one).",
		func(w http.ResponseWriter, r *http.Request) {
			data, reqErr := json.Marshal(endpoints)
			if reqErr != nil {
				logger.Errorf("Failed to serve endpoints: %v\n", reqErr)
				http.Error(w, reqErr.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Add("Content-Type", "application/json")
			w.Write(data)
		})

	handle("/files", "Returns a list of available files and a map of users per document.",
		func(w http.ResponseWriter, r *http.Request) {
			var reqErr error
			var users map[string][]string
			if users, reqErr = curator.GetUsers(time.Second); reqErr == nil {
				var data []byte
				data, reqErr = json.Marshal(struct {
					Paths []string            `json:"paths"`
					Users map[string][]string `json:"users"`
				}{
					Paths: authenticator.GetPaths(),
					Users: users,
				})
				if reqErr == nil {
					w.Write(data)
				}
			}
			if reqErr != nil {
				http.Error(w, reqErr.Error(), http.StatusInternalServerError)
				logger.Errorf("Failed to serve users: %v\n", reqErr)
				return
			}
			w.Header().Add("Content-Type", "application/json")
		})

	handle("/stats", "Lists all aggregated metrics as a json blob.", stats.JSONHandler())

	wwwPath := gopath.Join("/", *subdirPath)
	stripPath := ""
	if wwwPath != "/" {
		wwwPath = wwwPath + "/"
		stripPath = wwwPath
	}
	if len(*debugWWWDir) > 0 {
		logger.Warnf("Serving web files from alternative www dir: %v\n", *debugWWWDir)
		http.Handle(wwwPath, http.StripPrefix(stripPath, http.FileServer(http.Dir(*debugWWWDir))))
	} else {
		http.Handle(wwwPath, http.StripPrefix(stripPath, http.FileServer(assetFS())))
	}
	http.Handle(gopath.Join("/", *subdirPath, "/leaps/ws"),
		websocket.Handler(leaphttp.WebsocketHandler(curator, time.Second, logger, stats)))

	go func() {
		logger.Infof("Serving HTTP requests at: %v%v\n", *httpAddress, *subdirPath)
		if httperr := http.ListenAndServe(*httpAddress, nil); httperr != nil {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("HTTP listen error: %v\n", httperr))
		}
		closeChan <- true
	}()

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

	// Wait for termination signal
	select {
	case <-sigChan:
	case <-closeChan:
	}
}