Skip to main content
Glama

Storyden

by Southclaws
Mozilla Public License 2.0
227
nextjs.go2.33 kB
package frontend import ( "bufio" "context" "io" "log/slog" "os" "os/exec" "strings" "sync" "time" ) var fallbackTimeout = 5 * time.Second type NextjsProcess struct { logger *slog.Logger ready chan struct{} once sync.Once } func (p *NextjsProcess) Ready() <-chan struct{} { return p.ready } func (p *NextjsProcess) Run(ctx context.Context, path string) { p.ready = make(chan struct{}) cmd := exec.CommandContext(ctx, "node", path) cmd.Stderr = os.Stderr stdoutPipe, err := cmd.StdoutPipe() if err != nil { panic(err) } p.logger.Info("storyden frontend server starting", slog.String("path", path)) err = cmd.Start() if err != nil { panic(err) } go p.waitForReady(stdoutPipe) go p.fallbackWait() err = cmd.Wait() if err != nil { p.logger.Error("frontend process exited with error", slog.Any("error", err)) } } func (p *NextjsProcess) waitForReady(stdout io.Reader) { scanner := bufio.NewScanner(stdout) for scanner.Scan() { line := scanner.Text() os.Stdout.WriteString(line + "\n") // NOTE: This is a Next.js specific log line we're looking for. THIS // MIGHT CHANGE! And if it does, this will break. To account for this, // there is a fallback after 5 seconds to simply mark the app as ready // and allow requests through. If this does happen, a warning is logged. // It would be nice to have a better startup signal but... another day. if strings.Contains(line, "Ready in") { p.once.Do(func() { close(p.ready) p.logger.Info("frontend server is ready") }) } } if err := scanner.Err(); err != nil { p.logger.Error("error reading frontend output", slog.Any("error", err)) } } func (p *NextjsProcess) fallbackWait() { // Fallback: If we don't see the "Ready in" log line in 30 seconds, just // assume the frontend is ready anyway. This is to prevent the entire app // from being unusable if the log line changes or something else goes wrong. // We still log an error in that case, but we don't want to block the entire // app from working. select { case <-p.ready: case <-time.After(fallbackTimeout): p.once.Do(func() { close(p.ready) p.logger.Warn("timeout waiting for frontend to be ready, assuming it's ready anyway, if you see this message please open an issue! https://github.com/Southclaws/storyden/issues/new") }) } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server