125 lines
3.7 KiB
Go
125 lines
3.7 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/microsoft/typescript-go/internal/bundled"
|
|
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
|
"github.com/microsoft/typescript-go/internal/project"
|
|
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
|
)
|
|
|
|
// StdioServerOptions configures the STDIO-based API server.
|
|
type StdioServerOptions struct {
|
|
In io.ReadCloser
|
|
Out io.WriteCloser
|
|
Err io.Writer
|
|
Cwd string
|
|
DefaultLibraryPath string
|
|
// PipePath, if set, listens on a named pipe (Windows) or Unix domain
|
|
// socket instead of using In/Out for communication.
|
|
PipePath string
|
|
// Callbacks specifies which filesystem operations should be delegated
|
|
// to the client (e.g., "readFile", "fileExists"). Empty means no callbacks.
|
|
Callbacks []string
|
|
// Async enables JSON-RPC protocol with async connection handling.
|
|
// When false (default), uses MessagePack protocol with sync connection.
|
|
Async bool
|
|
// CollectTiming enables per-request server processing-time measurement.
|
|
// When enabled, the server accumulates each request's processing time into
|
|
// running totals and a recent-request ring buffer. Response messages are
|
|
// left unchanged; the client folds this data into its own timing snapshot
|
|
// on demand via getServerTiming / resetServerTiming requests.
|
|
CollectTiming bool
|
|
}
|
|
|
|
// StdioServer runs an API session over STDIO using MessagePack protocol.
|
|
// This is the entry point for the synchronous STDIO-based API used by
|
|
// native TypeScript tooling integration.
|
|
type StdioServer struct {
|
|
options *StdioServerOptions
|
|
}
|
|
|
|
// NewStdioServer creates a new STDIO-based API server.
|
|
func NewStdioServer(options *StdioServerOptions) *StdioServer {
|
|
if options.Cwd == "" {
|
|
panic("StdioServerOptions.Cwd is required")
|
|
}
|
|
|
|
return &StdioServer{
|
|
options: options,
|
|
}
|
|
}
|
|
|
|
// Run starts the server and blocks until the connection closes.
|
|
func (s *StdioServer) Run(ctx context.Context) error {
|
|
var transport Transport
|
|
if s.options.PipePath != "" {
|
|
t, err := NewPipeTransport(s.options.PipePath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create pipe transport: %w", err)
|
|
}
|
|
defer t.Close()
|
|
transport = t
|
|
} else {
|
|
t := NewStdioTransport(s.options.In, s.options.Out)
|
|
defer t.Close()
|
|
transport = t
|
|
}
|
|
|
|
fs := bundled.WrapFS(osvfs.FS())
|
|
|
|
// Wrap the base FS with callbackFS if callbacks are requested
|
|
var callbackFS *callbackFS
|
|
if len(s.options.Callbacks) > 0 {
|
|
callbackFS = newCallbackFS(fs, s.options.Callbacks)
|
|
fs = callbackFS
|
|
}
|
|
|
|
projectSession := project.NewSession(&project.SessionInit{
|
|
BackgroundCtx: ctx,
|
|
Logger: nil, // TODO: Add logging support
|
|
FS: fs,
|
|
Options: &project.SessionOptions{
|
|
CurrentDirectory: s.options.Cwd,
|
|
DefaultLibraryPath: s.options.DefaultLibraryPath,
|
|
PositionEncoding: lsproto.PositionEncodingKindUTF8,
|
|
LoggingEnabled: false,
|
|
},
|
|
})
|
|
|
|
session := NewSession(projectSession, &SessionOptions{
|
|
UseBinaryResponses: !s.options.Async, // Only msgpack uses binary responses
|
|
})
|
|
defer session.Close()
|
|
|
|
// Accept connection from transport
|
|
rwc, err := transport.Accept()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to accept connection: %w", err)
|
|
}
|
|
|
|
// Create protocol and connection based on async mode
|
|
var conn Conn
|
|
if s.options.Async {
|
|
protocol := NewJSONRPCProtocol(rwc)
|
|
asyncConn := NewAsyncConnWithProtocol(rwc, protocol, session)
|
|
asyncConn.SetCollectTiming(s.options.CollectTiming)
|
|
conn = asyncConn
|
|
} else {
|
|
protocol := NewMessagePackProtocol(rwc)
|
|
syncConn := NewSyncConn(rwc, protocol, session)
|
|
syncConn.SetCollectTiming(s.options.CollectTiming)
|
|
conn = syncConn
|
|
}
|
|
|
|
// If callbacks are enabled, set the connection on the FS
|
|
if callbackFS != nil {
|
|
callbackFS.SetConnection(ctx, conn)
|
|
}
|
|
|
|
return conn.Run(ctx)
|
|
}
|