Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
彭彦祖
code-server
提交
68fe085a
C
code-server
项目概览
彭彦祖
/
code-server
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
code-server
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
68fe085a
编写于
6月 28, 2019
作者:
A
Asher
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add channels
上级
48614056
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
261 addition
and
36 deletion
+261
-36
channel.ts
channel.ts
+137
-0
connection.ts
connection.ts
+47
-6
entry.ts
entry.ts
+4
-0
main.js
main.js
+1
-1
server.ts
server.ts
+65
-20
socket.ts
socket.ts
+7
-9
未找到文件。
channel.ts
0 → 100644
浏览文件 @
68fe085a
import
*
as
path
from
"
path
"
;
import
{
Emitter
,
Event
}
from
"
vs/base/common/event
"
;
import
{
OS
}
from
"
vs/base/common/platform
"
;
import
{
URI
}
from
"
vs/base/common/uri
"
;
import
{
IServerChannel
}
from
"
vs/base/parts/ipc/common/ipc
"
;
import
{
IDiagnosticInfo
}
from
"
vs/platform/diagnostics/common/diagnosticsService
"
;
import
{
IEnvironmentService
}
from
"
vs/platform/environment/common/environment
"
;
import
{
FileDeleteOptions
,
FileOverwriteOptions
,
FileType
,
IStat
,
IWatchOptions
,
FileOpenOptions
}
from
"
vs/platform/files/common/files
"
;
import
{
IRemoteAgentEnvironment
}
from
"
vs/platform/remote/common/remoteAgentEnvironment
"
;
/**
* See: src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts.
*/
export
class
FileProviderChannel
implements
IServerChannel
{
public
listen
(
_context
:
any
,
event
:
string
):
Event
<
any
>
{
switch
(
event
)
{
case
"
filechange
"
:
// TODO: not sure what to do here yet
return
new
Emitter
().
event
;
}
throw
new
Error
(
`Invalid listen "
${
event
}
"`
);
}
public
call
(
_
:
unknown
,
command
:
string
,
args
?:
any
):
Promise
<
any
>
{
console
.
log
(
"
got call
"
,
command
,
args
);
switch
(
command
)
{
case
"
stat
"
:
return
this
.
stat
(
args
[
0
]);
case
"
open
"
:
return
this
.
open
(
args
[
0
],
args
[
1
]);
case
"
close
"
:
return
this
.
close
(
args
[
0
]);
case
"
read
"
:
return
this
.
read
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
]);
case
"
write
"
:
return
this
.
write
(
args
[
0
],
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
]);
case
"
delete
"
:
return
this
.
delete
(
args
[
0
],
args
[
1
]);
case
"
mkdir
"
:
return
this
.
mkdir
(
args
[
0
]);
case
"
readdir
"
:
return
this
.
readdir
(
args
[
0
]);
case
"
rename
"
:
return
this
.
rename
(
args
[
0
],
args
[
1
],
args
[
2
]);
case
"
copy
"
:
return
this
.
copy
(
args
[
0
],
args
[
1
],
args
[
2
]);
case
"
watch
"
:
return
this
.
watch
(
args
[
0
],
args
[
1
]);
case
"
unwatch
"
:
return
this
.
unwatch
(
args
[
0
]),
args
[
1
];
}
throw
new
Error
(
`Invalid call "
${
command
}
"`
);
}
private
async
stat
(
resource
:
URI
):
Promise
<
IStat
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
open
(
resource
:
URI
,
opts
:
FileOpenOptions
):
Promise
<
number
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
close
(
fd
:
number
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
read
(
fd
:
number
,
pos
:
number
,
data
:
Uint8Array
,
offset
:
number
,
length
:
number
):
Promise
<
number
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
write
(
fd
:
number
,
pos
:
number
,
data
:
Uint8Array
,
offset
:
number
,
length
:
number
):
Promise
<
number
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
delete
(
resource
:
URI
,
opts
:
FileDeleteOptions
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
mkdir
(
resource
:
URI
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
readdir
(
resource
:
URI
):
Promise
<
[
string
,
FileType
][]
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
async
rename
(
resource
:
URI
,
target
:
URI
,
opts
:
FileOverwriteOptions
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
copy
(
resource
:
URI
,
target
:
URI
,
opts
:
FileOverwriteOptions
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
watch
(
resource
:
URI
,
opts
:
IWatchOptions
):
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
unwatch
(
resource
:
URI
):
void
{
throw
new
Error
(
"
not implemented
"
);
}
}
/**
* See: src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts.
*/
export
class
ExtensionEnvironmentChannel
implements
IServerChannel
{
public
constructor
(
private
readonly
environment
:
IEnvironmentService
)
{}
public
listen
(
_context
:
any
,
event
:
string
):
Event
<
any
>
{
throw
new
Error
(
`Invalid listen "
${
event
}
"`
);
}
public
call
(
_
:
unknown
,
command
:
string
,
args
?:
any
):
Promise
<
any
>
{
switch
(
command
)
{
case
"
getEnvironmentData
"
:
return
this
.
getEnvironmentData
();
case
"
getDiagnosticInfo
"
:
return
this
.
getDiagnosticInfo
();
case
"
disableTelemetry
"
:
return
this
.
disableTelemetry
();
}
throw
new
Error
(
`Invalid call "
${
command
}
"`
);
}
private
async
getEnvironmentData
():
Promise
<
IRemoteAgentEnvironment
>
{
return
{
pid
:
process
.
pid
,
appRoot
:
URI
.
file
(
this
.
environment
.
appRoot
),
appSettingsHome
:
this
.
environment
.
appSettingsHome
,
settingsPath
:
this
.
environment
.
machineSettingsHome
,
logsPath
:
URI
.
file
(
this
.
environment
.
logsPath
),
extensionsPath
:
URI
.
file
(
this
.
environment
.
extensionsPath
),
extensionHostLogsPath
:
URI
.
file
(
path
.
join
(
this
.
environment
.
logsPath
,
"
extension-host
"
)),
// TODO
globalStorageHome
:
URI
.
file
(
this
.
environment
.
globalStorageHome
),
userHome
:
URI
.
file
(
this
.
environment
.
userHome
),
extensions
:
[],
// TODO
os
:
OS
,
};
}
private
getDiagnosticInfo
():
Promise
<
IDiagnosticInfo
>
{
throw
new
Error
(
"
not implemented
"
);
}
private
disableTelemetry
():
Promise
<
void
>
{
throw
new
Error
(
"
not implemented
"
);
}
}
connection.ts
浏览文件 @
68fe085a
import
{
ClientConnectionEvent
}
from
"
vs/base/parts/ipc/common/ipc
"
;
import
{
ConnectionType
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
import
{
Emitter
}
from
"
vs/base/common/event
"
;
import
{
PersistentProtocol
,
ISocket
}
from
"
vs/base/parts/ipc/common/ipc.net
"
;
import
{
VSBuffer
}
from
"
vs/base/common/buffer
"
;
export
interface
Server
{
readonly
_onDidClientConnect
:
Emitter
<
ClientConnectionEvent
>
;
readonly
connections
:
Map
<
ConnectionType
,
Map
<
string
,
Connection
>>
;
}
export
abstract
class
Connection
{
pr
otected
readonly
_onClose
=
new
Emitter
<
void
>
();
pr
ivate
readonly
_onClose
=
new
Emitter
<
void
>
();
public
readonly
onClose
=
this
.
_onClose
.
event
;
public
constructor
(
private
readonly
protocol
:
PersistentProtocol
)
{
private
timeout
:
NodeJS
.
Timeout
|
undefined
;
private
readonly
wait
=
1000
*
60
*
60
;
public
constructor
(
protected
readonly
server
:
Server
,
private
readonly
protocol
:
PersistentProtocol
,
)
{
// onClose seems to mean we want to disconnect, so dispose immediately.
this
.
protocol
.
onClose
(()
=>
this
.
dispose
());
// If the socket closes, we want to wait before disposing so we can
// reconnect.
this
.
protocol
.
onSocketClose
(()
=>
{
// TODO: eventually we'll want to clean up the connection if nothing
// ever connects back to it
this
.
timeout
=
setTimeout
(()
=>
{
this
.
dispose
();
},
this
.
wait
);
});
}
/**
* Completely close and clean up the connection. Should only do this once we
* don't need or want the connection. It cannot be re-used after this.
*/
public
dispose
():
void
{
this
.
protocol
.
sendDisconnect
();
this
.
protocol
.
getSocket
().
end
();
this
.
protocol
.
dispose
();
this
.
_onClose
.
fire
();
}
public
reconnect
(
socket
:
ISocket
,
buffer
:
VSBuffer
):
void
{
clearTimeout
(
this
.
timeout
as
any
);
// Not sure why the type doesn't work.
this
.
protocol
.
beginAcceptReconnection
(
socket
,
buffer
);
this
.
protocol
.
endAcceptReconnection
();
}
}
/**
* The management connection is used for all the IPC channels.
*/
export
class
ManagementConnection
extends
Connection
{
// in here they accept the connection
// to the ipc of the RemoteServer
public
constructor
(
server
:
Server
,
protocol
:
PersistentProtocol
)
{
super
(
server
,
protocol
);
// This will communicate back to the IPCServer that a new client has
// connected.
this
.
server
.
_onDidClientConnect
.
fire
({
protocol
,
onDidClientDisconnect
:
this
.
onClose
,
});
}
}
export
class
ExtensionHostConnection
extends
Connection
{
...
...
entry.ts
0 → 100644
浏览文件 @
68fe085a
import
{
Server
}
from
"
./server
"
;
const
server
=
new
Server
();
server
.
listen
();
main.js
浏览文件 @
68fe085a
require
(
"
../../bootstrap-amd
"
).
load
(
"
vs/server/
server
"
);
require
(
"
../../bootstrap-amd
"
).
load
(
"
vs/server/
entry
"
);
server.ts
浏览文件 @
68fe085a
...
...
@@ -5,19 +5,29 @@ import * as path from "path";
import
*
as
util
from
"
util
"
;
import
*
as
url
from
"
url
"
;
import
{
Connection
}
from
"
vs/server/connection
"
;
import
{
ConnectionType
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
import
{
Emitter
}
from
"
vs/base/common/event
"
;
import
{
ClientConnectionEvent
}
from
"
vs/base/parts/ipc/common/ipc
"
;
import
{
Socket
,
Server
as
IServer
}
from
"
vs/server/socket
"
;
import
{
IPCServer
,
ClientConnectionEvent
}
from
"
vs/base/parts/ipc/common/ipc
"
;
import
{
validatePaths
}
from
"
vs/code/node/paths
"
;
import
{
parseMainProcessArgv
}
from
"
vs/platform/environment/node/argvHelper
"
;
import
{
ParsedArgs
}
from
"
vs/platform/environment/common/environment
"
;
import
{
EnvironmentService
}
from
"
vs/platform/environment/node/environmentService
"
;
import
{
InstantiationService
}
from
"
vs/platform/instantiation/common/instantiationService
"
;
import
{
ConsoleLogMainService
}
from
"
vs/platform/log/common/log
"
;
import
{
LogLevelSetterChannel
}
from
"
vs/platform/log/common/logIpc
"
;
import
{
ConnectionType
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
import
{
REMOTE_FILE_SYSTEM_CHANNEL_NAME
}
from
"
vs/platform/remote/common/remoteAgentFileSystemChannel
"
;
import
{
Connection
,
Server
as
IServer
}
from
"
vs/server/connection
"
;
import
{
ExtensionEnvironmentChannel
,
FileProviderChannel
}
from
"
vs/server/channel
"
;
import
{
Socket
}
from
"
vs/server/socket
"
;
enum
HttpCode
{
e
xport
e
num
HttpCode
{
Ok
=
200
,
NotFound
=
404
,
BadRequest
=
400
,
}
class
HttpError
extends
Error
{
export
class
HttpError
extends
Error
{
public
constructor
(
message
:
string
,
public
readonly
code
:
number
)
{
super
(
message
);
// @ts-ignore
...
...
@@ -26,14 +36,24 @@ class HttpError extends Error {
}
}
class
Server
implements
IServer
{
private
readonly
_onDidClientConnect
=
new
Emitter
<
ClientConnectionEvent
>
();
export
class
Server
implements
IServer
{
// When a new client connects, it will fire this event which is used in the
// IPC server which manages channels.
public
readonly
_onDidClientConnect
=
new
Emitter
<
ClientConnectionEvent
>
();
public
readonly
onDidClientConnect
=
this
.
_onDidClientConnect
.
event
;
private
readonly
rootPath
=
path
.
resolve
(
__dirname
,
"
../../..
"
);
// This is separate instead of just extending this class since we can't
// use properties in the super call. This manages channels.
private
readonly
ipc
=
new
IPCServer
(
this
.
onDidClientConnect
);
// The web server.
private
readonly
server
:
http
.
Server
;
// Persistent connections. These can reconnect within a timeout. Individual
// sockets will add connections made through them to this map and remove them
// when they close.
public
readonly
connections
=
new
Map
<
ConnectionType
,
Map
<
string
,
Connection
>>
();
public
constructor
()
{
...
...
@@ -52,17 +72,45 @@ class Server implements IServer {
});
this
.
server
.
on
(
"
upgrade
"
,
(
request
,
socket
)
=>
{
this
.
handleUpgrade
(
request
,
socket
);
try
{
const
nodeSocket
=
this
.
handleUpgrade
(
request
,
socket
);
nodeSocket
.
handshake
(
this
);
}
catch
(
error
)
{
socket
.
end
(
error
.
message
);
}
});
this
.
server
.
on
(
"
error
"
,
(
error
)
=>
{
console
.
error
(
error
);
process
.
exit
(
1
);
});
}
public
dispose
():
void
{
this
.
connections
.
clear
();
let
args
:
ParsedArgs
;
try
{
args
=
parseMainProcessArgv
(
process
.
argv
);
args
=
validatePaths
(
args
);
}
catch
(
error
)
{
console
.
error
(
error
.
message
);
return
process
.
exit
(
1
);
}
const
environmentService
=
new
EnvironmentService
(
args
,
process
.
execPath
);
// TODO: might want to use spdlog.
const
logService
=
new
ConsoleLogMainService
();
this
.
ipc
.
registerChannel
(
"
loglevel
"
,
new
LogLevelSetterChannel
(
logService
));
const
instantiationService
=
new
InstantiationService
();
instantiationService
.
invokeFunction
(()
=>
{
this
.
ipc
.
registerChannel
(
REMOTE_FILE_SYSTEM_CHANNEL_NAME
,
new
FileProviderChannel
(),
);
this
.
ipc
.
registerChannel
(
"
remoteextensionsenvironment
"
,
new
ExtensionEnvironmentChannel
(
environmentService
),
);
});
}
private
async
handleRequest
(
request
:
http
.
IncomingMessage
):
Promise
<
string
|
Buffer
>
{
...
...
@@ -118,9 +166,9 @@ class Server implements IServer {
}
}
private
handleUpgrade
(
request
:
http
.
IncomingMessage
,
socket
:
net
.
Socket
):
void
{
private
handleUpgrade
(
request
:
http
.
IncomingMessage
,
socket
:
net
.
Socket
):
Socket
{
if
(
request
.
headers
.
upgrade
!==
"
websocket
"
)
{
return
socket
.
end
(
"
HTTP/1.1 400 Bad Request
"
);
throw
new
Error
(
"
HTTP/1.1 400 Bad Request
"
);
}
const
options
=
{
...
...
@@ -144,11 +192,11 @@ class Server implements IServer {
const
nodeSocket
=
new
Socket
(
socket
,
options
);
nodeSocket
.
upgrade
(
request
.
headers
[
"
sec-websocket-key
"
]
as
string
);
nodeSocket
.
handshake
(
this
);
return
nodeSocket
;
}
public
listen
():
void
{
const
port
=
8443
;
public
listen
(
port
:
number
=
8443
):
void
{
this
.
server
.
listen
(
port
,
()
=>
{
const
address
=
this
.
server
.
address
();
const
location
=
typeof
address
===
"
string
"
...
...
@@ -159,6 +207,3 @@ class Server implements IServer {
});
}
}
const
server
=
new
Server
();
server
.
listen
();
socket.ts
浏览文件 @
68fe085a
import
*
as
crypto
from
"
crypto
"
;
import
*
as
net
from
"
net
"
;
import
{
AuthRequest
,
ConnectionType
,
ConnectionTypeRequest
,
HandshakeMessage
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
import
{
VSBuffer
}
from
"
vs/base/common/buffer
"
;
import
{
NodeSocket
,
WebSocketNodeSocket
}
from
"
vs/base/parts/ipc/node/ipc.net
"
;
import
{
PersistentProtocol
,
ISocket
}
from
"
vs/base/parts/ipc/common/ipc.net
"
;
import
{
VSBuffer
}
from
"
vs/base/common/buffer
"
;
import
{
Connection
,
ExtensionHostConnection
,
ManagementConnection
}
from
"
vs/server/connection
"
;
import
{
AuthRequest
,
ConnectionType
,
ConnectionTypeRequest
,
HandshakeMessage
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
import
{
ExtensionHostConnection
,
ManagementConnection
,
Server
}
from
"
vs/server/connection
"
;
export
interface
SocketOptions
{
readonly
reconnectionToken
:
string
;
...
...
@@ -12,10 +14,6 @@ export interface SocketOptions {
readonly
skipWebSocketFrames
:
boolean
;
}
export
interface
Server
{
readonly
connections
:
Map
<
ConnectionType
,
Map
<
string
,
Connection
>>
;
}
export
class
Socket
{
private
nodeSocket
:
ISocket
;
public
protocol
:
PersistentProtocol
;
...
...
@@ -114,8 +112,8 @@ export class Socket {
this
.
sendControl
(
ok
);
const
connection
=
message
.
desiredConnectionType
===
ConnectionType
.
Management
?
new
ManagementConnection
(
this
.
protocol
)
:
new
ExtensionHostConnection
(
this
.
protocol
);
?
new
ManagementConnection
(
server
,
this
.
protocol
)
:
new
ExtensionHostConnection
(
server
,
this
.
protocol
);
connections
.
set
(
this
.
options
.
reconnectionToken
,
connection
);
connection
.
onClose
(()
=>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录