Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
myhjmzy
code-server
提交
48614056
C
code-server
项目概览
myhjmzy
/
code-server
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
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,发现更多精彩内容 >>
未验证
提交
48614056
编写于
6月 27, 2019
作者:
A
Asher
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Initial connection handling
上级
310bfe50
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
363 addition
and
85 deletion
+363
-85
README.md
README.md
+5
-0
connection.ts
connection.ts
+28
-0
main.js
main.js
+1
-0
server.ts
server.ts
+164
-0
socket.ts
socket.ts
+161
-0
tslint.json
tslint.json
+4
-85
未找到文件。
README.md
浏览文件 @
48614056
...
...
@@ -52,6 +52,11 @@ How to [secure your setup](/doc/security/ssl.md).
## Development
-
Clone this as
`vs/src/server`
in the VS Code source.
-
Run
`yarn watch-client`
in the VS Code root.
-
Run
`node out/vs/server/main.js`
.
-
Visit
`http://localhost:8443`
.
### Known Issues
-
Creating custom VS Code extensions and debugging them doesn't work.
...
...
connection.ts
0 → 100644
浏览文件 @
48614056
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
abstract
class
Connection
{
protected
readonly
_onClose
=
new
Emitter
<
void
>
();
public
readonly
onClose
=
this
.
_onClose
.
event
;
public
constructor
(
private
readonly
protocol
:
PersistentProtocol
)
{
this
.
protocol
.
onSocketClose
(()
=>
{
// TODO: eventually we'll want to clean up the connection if nothing
// ever connects back to it
});
}
public
reconnect
(
socket
:
ISocket
,
buffer
:
VSBuffer
):
void
{
this
.
protocol
.
beginAcceptReconnection
(
socket
,
buffer
);
this
.
protocol
.
endAcceptReconnection
();
}
}
export
class
ManagementConnection
extends
Connection
{
// in here they accept the connection
// to the ipc of the RemoteServer
}
export
class
ExtensionHostConnection
extends
Connection
{
}
main.js
0 → 100644
浏览文件 @
48614056
require
(
"
../../bootstrap-amd
"
).
load
(
"
vs/server/server
"
);
server.ts
0 → 100644
浏览文件 @
48614056
import
*
as
fs
from
"
fs
"
;
import
*
as
http
from
"
http
"
;
import
*
as
net
from
"
net
"
;
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
"
;
enum
HttpCode
{
Ok
=
200
,
NotFound
=
404
,
BadRequest
=
400
,
}
class
HttpError
extends
Error
{
public
constructor
(
message
:
string
,
public
readonly
code
:
number
)
{
super
(
message
);
// @ts-ignore
this
.
name
=
this
.
constructor
.
name
;
Error
.
captureStackTrace
(
this
,
this
.
constructor
);
}
}
class
Server
implements
IServer
{
private
readonly
_onDidClientConnect
=
new
Emitter
<
ClientConnectionEvent
>
();
public
readonly
onDidClientConnect
=
this
.
_onDidClientConnect
.
event
;
private
readonly
rootPath
=
path
.
resolve
(
__dirname
,
"
../../..
"
);
private
readonly
server
:
http
.
Server
;
public
readonly
connections
=
new
Map
<
ConnectionType
,
Map
<
string
,
Connection
>>
();
public
constructor
()
{
this
.
server
=
http
.
createServer
(
async
(
request
,
response
):
Promise
<
void
>
=>
{
try
{
const
content
=
await
this
.
handleRequest
(
request
);
response
.
writeHead
(
HttpCode
.
Ok
,
{
"
Cache-Control
"
:
"
max-age=86400
"
,
// TODO: ETag?
});
response
.
end
(
content
);
}
catch
(
error
)
{
response
.
writeHead
(
typeof
error
.
code
===
"
number
"
?
error
.
code
:
500
);
response
.
end
(
error
.
message
);
}
});
this
.
server
.
on
(
"
upgrade
"
,
(
request
,
socket
)
=>
{
this
.
handleUpgrade
(
request
,
socket
);
});
this
.
server
.
on
(
"
error
"
,
(
error
)
=>
{
console
.
error
(
error
);
process
.
exit
(
1
);
});
}
public
dispose
():
void
{
this
.
connections
.
clear
();
}
private
async
handleRequest
(
request
:
http
.
IncomingMessage
):
Promise
<
string
|
Buffer
>
{
if
(
request
.
method
!==
"
GET
"
)
{
throw
new
HttpError
(
`Unsupported method
${
request
.
method
}
`
,
HttpCode
.
BadRequest
,
);
}
const
requestPath
=
url
.
parse
(
request
.
url
||
""
).
pathname
||
"
/
"
;
if
(
requestPath
===
"
/
"
)
{
const
htmlPath
=
path
.
join
(
this
.
rootPath
,
'
out/vs/code/browser/workbench/workbench.html
'
,
);
let
html
=
await
util
.
promisify
(
fs
.
readFile
)(
htmlPath
,
"
utf8
"
);
const
options
=
{
WEBVIEW_ENDPOINT
:
{},
WORKBENCH_WEB_CONGIGURATION
:
{
remoteAuthority
:
request
.
headers
.
host
,
},
REMOTE_USER_DATA_URI
:
{
scheme
:
"
http
"
,
authority
:
request
.
headers
.
host
,
path
:
"
/
"
,
},
PRODUCT_CONFIGURATION
:
{},
CONNECTION_AUTH_TOKEN
:
{}
};
Object
.
keys
(
options
).
forEach
((
key
)
=>
{
html
=
html
.
replace
(
`"{{
${
key
}
}}"`
,
`'
${
JSON
.
stringify
(
options
[
key
])}
'`
);
});
html
=
html
.
replace
(
'
{{WEBVIEW_ENDPOINT}}
'
,
JSON
.
stringify
(
options
.
WEBVIEW_ENDPOINT
));
return
html
;
}
try
{
const
content
=
await
util
.
promisify
(
fs
.
readFile
)(
path
.
join
(
this
.
rootPath
,
requestPath
),
);
return
content
;
}
catch
(
error
)
{
if
(
error
.
code
===
"
ENOENT
"
||
error
.
code
===
"
EISDIR
"
)
{
throw
new
HttpError
(
"
Not found
"
,
HttpCode
.
NotFound
);
}
throw
error
;
}
}
private
handleUpgrade
(
request
:
http
.
IncomingMessage
,
socket
:
net
.
Socket
):
void
{
if
(
request
.
headers
.
upgrade
!==
"
websocket
"
)
{
return
socket
.
end
(
"
HTTP/1.1 400 Bad Request
"
);
}
const
options
=
{
reconnectionToken
:
""
,
reconnection
:
false
,
skipWebSocketFrames
:
false
,
};
if
(
request
.
url
)
{
const
query
=
url
.
parse
(
request
.
url
,
true
).
query
;
if
(
query
.
reconnectionToken
)
{
options
.
reconnectionToken
=
query
.
reconnectionToken
as
string
;
}
if
(
query
.
reconnection
===
"
true
"
)
{
options
.
reconnection
=
true
;
}
if
(
query
.
skipWebSocketFrames
===
"
true
"
)
{
options
.
skipWebSocketFrames
=
true
;
}
}
const
nodeSocket
=
new
Socket
(
socket
,
options
);
nodeSocket
.
upgrade
(
request
.
headers
[
"
sec-websocket-key
"
]
as
string
);
nodeSocket
.
handshake
(
this
);
}
public
listen
():
void
{
const
port
=
8443
;
this
.
server
.
listen
(
port
,
()
=>
{
const
address
=
this
.
server
.
address
();
const
location
=
typeof
address
===
"
string
"
?
address
:
`port
${
address
.
port
}
`
;
console
.
log
(
`Listening on
${
location
}
`
);
console
.
log
(
`Serving
${
this
.
rootPath
}
`
);
});
}
}
const
server
=
new
Server
();
server
.
listen
();
socket.ts
0 → 100644
浏览文件 @
48614056
import
*
as
crypto
from
"
crypto
"
;
import
*
as
net
from
"
net
"
;
import
{
AuthRequest
,
ConnectionType
,
ConnectionTypeRequest
,
HandshakeMessage
}
from
"
vs/platform/remote/common/remoteAgentConnection
"
;
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
"
;
export
interface
SocketOptions
{
readonly
reconnectionToken
:
string
;
readonly
reconnection
:
boolean
;
readonly
skipWebSocketFrames
:
boolean
;
}
export
interface
Server
{
readonly
connections
:
Map
<
ConnectionType
,
Map
<
string
,
Connection
>>
;
}
export
class
Socket
{
private
nodeSocket
:
ISocket
;
public
protocol
:
PersistentProtocol
;
public
constructor
(
private
readonly
socket
:
net
.
Socket
,
private
readonly
options
:
SocketOptions
)
{
socket
.
on
(
"
error
"
,
()
=>
this
.
dispose
());
this
.
nodeSocket
=
new
NodeSocket
(
socket
);
if
(
!
this
.
options
.
skipWebSocketFrames
)
{
this
.
nodeSocket
=
new
WebSocketNodeSocket
(
this
.
nodeSocket
as
NodeSocket
);
}
this
.
protocol
=
new
PersistentProtocol
(
this
.
nodeSocket
);
}
/**
* Upgrade the connection into a web socket.
*/
public
upgrade
(
secWebsocketKey
:
string
):
void
{
// This magic value is specified by the websocket spec.
const
magic
=
"
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
"
;
const
reply
=
crypto
.
createHash
(
"
sha1
"
)
.
update
(
secWebsocketKey
+
magic
)
.
digest
(
"
base64
"
);
this
.
socket
.
write
([
"
HTTP/1.1 101 Switching Protocols
"
,
"
Upgrade: websocket
"
,
"
Connection: Upgrade
"
,
`Sec-WebSocket-Accept:
${
reply
}
`
,
].
join
(
"
\r\n
"
)
+
"
\r\n\r\n
"
);
}
public
dispose
():
void
{
this
.
nodeSocket
.
dispose
();
this
.
protocol
.
dispose
();
this
.
nodeSocket
=
undefined
!
;
this
.
protocol
=
undefined
!
;
}
public
handshake
(
server
:
Server
):
void
{
const
handler
=
this
.
protocol
.
onControlMessage
((
rawMessage
)
=>
{
const
message
=
JSON
.
parse
(
rawMessage
.
toString
());
switch
(
message
.
type
)
{
case
"
auth
"
:
return
this
.
authenticate
(
message
);
case
"
connectionType
"
:
handler
.
dispose
();
return
this
.
connect
(
message
,
server
);
case
"
default
"
:
return
this
.
dispose
();
}
});
}
/**
* TODO: This ignores the authentication process entirely for now.
*/
private
authenticate
(
_message
:
AuthRequest
):
void
{
this
.
sendControl
({
type
:
"
sign
"
,
data
:
""
,
});
}
private
connect
(
message
:
ConnectionTypeRequest
,
server
:
Server
):
void
{
switch
(
message
.
desiredConnectionType
)
{
case
ConnectionType
.
ExtensionHost
:
case
ConnectionType
.
Management
:
const
debugPort
=
this
.
getDebugPort
();
const
ok
=
message
.
desiredConnectionType
===
ConnectionType
.
ExtensionHost
?
(
debugPort
?
{
debugPort
}
:
{})
:
{
type
:
"
ok
"
};
if
(
!
server
.
connections
.
has
(
message
.
desiredConnectionType
))
{
server
.
connections
.
set
(
message
.
desiredConnectionType
,
new
Map
());
}
const
connections
=
server
.
connections
.
get
(
message
.
desiredConnectionType
)
!
;
if
(
this
.
options
.
reconnection
&&
connections
.
has
(
this
.
options
.
reconnectionToken
))
{
this
.
sendControl
(
ok
);
const
buffer
=
this
.
protocol
.
readEntireBuffer
();
this
.
protocol
.
dispose
();
return
connections
.
get
(
this
.
options
.
reconnectionToken
)
!
.
reconnect
(
this
.
nodeSocket
,
buffer
);
}
if
(
this
.
options
.
reconnection
||
connections
.
has
(
this
.
options
.
reconnectionToken
))
{
this
.
sendControl
({
type
:
"
error
"
,
reason
:
this
.
options
.
reconnection
?
"
Unrecognized reconnection token
"
:
"
Duplicate reconnection token
"
,
});
return
this
.
dispose
();
}
this
.
sendControl
(
ok
);
const
connection
=
message
.
desiredConnectionType
===
ConnectionType
.
Management
?
new
ManagementConnection
(
this
.
protocol
)
:
new
ExtensionHostConnection
(
this
.
protocol
);
connections
.
set
(
this
.
options
.
reconnectionToken
,
connection
);
connection
.
onClose
(()
=>
{
connections
.
delete
(
this
.
options
.
reconnectionToken
);
});
break
;
case
ConnectionType
.
Tunnel
:
return
this
.
tunnel
();
default
:
this
.
sendControl
({
type
:
"
error
"
,
reason
:
"
Unrecognized connection type
"
,
});
return
this
.
dispose
();
}
}
/**
* TODO: implement.
*/
private
tunnel
():
void
{
this
.
sendControl
({
type
:
"
error
"
,
reason
:
"
Tunnel is not implemented yet
"
,
});
this
.
dispose
();
}
/**
* TODO: implement.
*/
private
getDebugPort
():
number
|
undefined
{
return
undefined
;
}
/**
* Send a handshake message. In the case of the extension host, it just sends
* back a debug port.
*/
private
sendControl
(
message
:
HandshakeMessage
|
{
debugPort
?:
number
}
):
void
{
this
.
protocol
.
sendControl
(
VSBuffer
.
fromString
(
JSON
.
stringify
(
message
)));
}
}
tslint.json
浏览文件 @
48614056
{
"rulesDirectory"
:
"./rules/dist"
,
"rules"
:
{
"only-arrow-functions"
:
true
,
"curly-statement-newlines"
:
true
,
"no-block-padding"
:
true
,
"adjacent-overload-signatures"
:
true
,
"align"
:
true
,
"await-promise"
:
[
true
,
"Thenable"
],
"class-name"
:
true
,
"eofline"
:
true
,
"import-spacing"
:
true
,
"indent"
:
[
true
,
"tabs"
],
"no-angle-bracket-type-assertion"
:
false
,
"no-bitwise"
:
false
,
"no-any"
:
true
,
"newline-before-return"
:
true
,
"no-console"
:
true
,
"no-duplicate-imports"
:
true
,
"no-consecutive-blank-lines"
:
true
,
"no-empty"
:
true
,
"no-floating-promises"
:
true
,
"no-return-await"
:
true
,
"no-var-keyword"
:
true
,
"no-trailing-whitespace"
:
true
,
"no-redundant-jsdoc"
:
true
,
"no-implicit-dependencies"
:
false
,
"no-boolean-literal-compare"
:
true
,
"prefer-readonly"
:
true
,
"deprecation"
:
true
,
"semicolon"
:
true
,
"one-line"
:
[
true
,
"check-catch"
,
"check-finally"
,
"check-else"
,
"check-whitespace"
,
"check-open-brace"
],
"completed-docs"
:
{
"options"
:
[
true
,
"enums"
,
"functions"
,
"methods"
,
"classes"
],
"severity"
:
"warning"
},
"no-unused-expression"
:
[
true
,
"allow-fast-null-checks"
],
"curly"
:
[
true
],
"quotemark"
:
[
true
,
"double"
,
"avoid-escape"
,
"avoid-template"
"extends"
:
[
"../../../tslint.json"
],
"trailing-comma"
:
[
true
,
{
"multiline"
:
"always"
,
"singleline"
:
"never"
,
"esSpecCompliant"
:
true
}
],
"space-before-function-paren"
:
[
false
,
"always"
],
"member-access"
:
[
true
,
"check-accessor"
,
"check-constructor"
,
"check-parameter-property"
],
"typedef"
:
[
true
,
"call-signature"
,
"arrow-call-signature"
,
"parameter"
,
"property-declaration"
]
"rules"
:
{
"no-unexternalized-strings"
:
false
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录