Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2014-04-04 18:55:21 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
83f35d10b1205397b5f01853083a11720c76c3a3
83f35d10
1 parent
8d7877eb
add http delivery framework
隐藏空白字符变更
内嵌
并排对比
正在显示
7 个修改的文件
包含
316 行增加
和
63 行删除
trunk/conf/full.conf
trunk/src/app/srs_app_config.cpp
trunk/src/app/srs_app_config.hpp
trunk/src/app/srs_app_http.cpp
trunk/src/app/srs_app_http_conn.cpp
trunk/src/app/srs_app_http_conn.hpp
trunk/src/app/srs_app_json.hpp
trunk/conf/full.conf
查看文件 @
83f35d1
...
...
@@ -85,13 +85,6 @@ http_stream {
# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
# for which cannot identify the required vhost.
vhost
__
defaultVhost__
{
enabled
on
;
gop_cache
on
;
http
{
enabled
on
;
mount
/;
dir
./
objs
/
nginx
/
html
;
}
}
# vhost for http
...
...
@@ -103,9 +96,11 @@ vhost http.srs.com {
enabled
on
;
# the virtual directory root for this vhost to mount at
# for example, if mount to /hls, user access by http://server/hls
# default: /
mount
/
hls
;
# main dir of vhost,
# to delivery HTTP stream of this vhost.
# default: ./objs/nginx/html
dir
./
objs
/
nginx
/
html
;
}
}
...
...
trunk/src/app/srs_app_config.cpp
查看文件 @
83f35d1
...
...
@@ -286,7 +286,7 @@ int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
}
// see: ngx_conf_read_token
int
SrsConfDirective
::
read_token
(
SrsFileBuffer
*
buffer
,
std
::
vector
<
string
>&
args
)
int
SrsConfDirective
::
read_token
(
SrsFileBuffer
*
buffer
,
vector
<
string
>&
args
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -427,6 +427,11 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<string>& arg
return
ret
;
}
bool
SrsConfDirective
::
is_vhost
()
{
return
name
==
"vhost"
;
}
SrsConfig
::
SrsConfig
()
{
show_help
=
false
;
...
...
@@ -777,6 +782,11 @@ bool SrsConfig::get_deamon()
return
true
;
}
SrsConfDirective
*
SrsConfig
::
get_root
()
{
return
root
;
}
int
SrsConfig
::
get_max_connections
()
{
srs_assert
(
root
);
...
...
@@ -835,6 +845,21 @@ int SrsConfig::get_pithy_print_forwarder()
return
::
atoi
(
pithy
->
arg0
().
c_str
());
}
int
SrsConfig
::
get_pithy_print_encoder
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"encoder"
);
if
(
!
pithy
)
{
return
SRS_STAGE_ENCODER_INTERVAL_MS
;
}
pithy
=
pithy
->
get
(
"forwarder"
);
if
(
!
pithy
)
{
return
SRS_STAGE_ENCODER_INTERVAL_MS
;
}
return
::
atoi
(
pithy
->
arg0
().
c_str
());
}
int
SrsConfig
::
get_pithy_print_hls
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
...
...
@@ -850,6 +875,21 @@ int SrsConfig::get_pithy_print_hls()
return
::
atoi
(
pithy
->
arg0
().
c_str
());
}
int
SrsConfig
::
get_pithy_print_play
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
SRS_STAGE_PLAY_USER_INTERVAL_MS
;
}
pithy
=
pithy
->
get
(
"play"
);
if
(
!
pithy
)
{
return
SRS_STAGE_PLAY_USER_INTERVAL_MS
;
}
return
::
atoi
(
pithy
->
arg0
().
c_str
());
}
SrsConfDirective
*
SrsConfig
::
get_vhost
(
string
vhost
)
{
srs_assert
(
root
);
...
...
@@ -857,7 +897,7 @@ SrsConfDirective* SrsConfig::get_vhost(string vhost)
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
conf
->
name
!=
"vhost"
)
{
if
(
!
conf
->
is_vhost
()
)
{
continue
;
}
...
...
@@ -1116,7 +1156,7 @@ SrsConfDirective* SrsConfig::get_refer_publish(string vhost)
return
conf
->
get
(
"refer_publish"
);
}
int
SrsConfig
::
get_chunk_size
(
const
st
d
::
st
ring
&
vhost
)
int
SrsConfig
::
get_chunk_size
(
const
string
&
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
...
...
@@ -1271,7 +1311,7 @@ string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode)
return
conf
->
arg0
();
}
void
SrsConfig
::
get_transcode_engines
(
SrsConfDirective
*
transcode
,
std
::
vector
<
SrsConfDirective
*>&
engines
)
void
SrsConfig
::
get_transcode_engines
(
SrsConfDirective
*
transcode
,
vector
<
SrsConfDirective
*>&
engines
)
{
if
(
!
transcode
)
{
return
;
...
...
@@ -1414,7 +1454,7 @@ string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
return
conf
->
arg0
();
}
void
SrsConfig
::
get_engine_vparams
(
SrsConfDirective
*
engine
,
std
::
vector
<
string
>&
vparams
)
void
SrsConfig
::
get_engine_vparams
(
SrsConfDirective
*
engine
,
vector
<
string
>&
vparams
)
{
if
(
!
engine
)
{
return
;
...
...
@@ -1436,7 +1476,7 @@ void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<string>
}
}
void
SrsConfig
::
get_engine_vfilter
(
SrsConfDirective
*
engine
,
std
::
vector
<
string
>&
vfilter
)
void
SrsConfig
::
get_engine_vfilter
(
SrsConfDirective
*
engine
,
vector
<
string
>&
vfilter
)
{
if
(
!
engine
)
{
return
;
...
...
@@ -1514,7 +1554,7 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine)
return
::
atoi
(
conf
->
arg0
().
c_str
());
}
void
SrsConfig
::
get_engine_aparams
(
SrsConfDirective
*
engine
,
std
::
vector
<
string
>&
aparams
)
void
SrsConfig
::
get_engine_aparams
(
SrsConfDirective
*
engine
,
vector
<
string
>&
aparams
)
{
if
(
!
engine
)
{
return
;
...
...
@@ -1754,34 +1794,68 @@ int SrsConfig::get_http_stream_listen()
return
8080
;
}
int
SrsConfig
::
get_pithy_print_encoder
(
)
bool
SrsConfig
::
get_vhost_http_enabled
(
string
vhost
)
{
SrsConfDirective
*
pithy
=
root
->
get
(
"encoder"
);
if
(
!
pithy
)
{
return
SRS_STAGE_ENCODER_INTERVAL_MS
;
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
false
;
}
pithy
=
pithy
->
get
(
"forwarder"
);
if
(
!
pithy
)
{
return
SRS_STAGE_ENCODER_INTERVAL_MS
;
conf
=
conf
->
get
(
"http"
);
if
(
!
conf
)
{
return
false
;
}
return
::
atoi
(
pithy
->
arg0
().
c_str
());
conf
=
conf
->
get
(
"enabled"
);
if
(
!
conf
)
{
return
false
;
}
if
(
conf
->
arg0
()
==
"on"
)
{
return
true
;
}
return
false
;
}
int
SrsConfig
::
get_pithy_print_play
(
)
string
SrsConfig
::
get_vhost_http_mount
(
string
vhost
)
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
SRS_STAGE_PLAY_USER_INTERVAL_MS
;
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
SRS_CONF_DEFAULT_HTTP_MOUNT
;
}
pithy
=
pithy
->
get
(
"play"
);
if
(
!
pithy
)
{
return
SRS_STAGE_PLAY_USER_INTERVAL_MS
;
conf
=
conf
->
get
(
"http"
);
if
(
!
conf
)
{
return
SRS_CONF_DEFAULT_HTTP_MOUNT
;
}
return
::
atoi
(
pithy
->
arg0
().
c_str
());
conf
=
conf
->
get
(
"mount"
);
if
(
!
conf
||
conf
->
arg0
().
empty
())
{
return
SRS_CONF_DEFAULT_HTTP_MOUNT
;
}
return
conf
->
arg0
();
}
string
SrsConfig
::
get_vhost_http_dir
(
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
SRS_CONF_DEFAULT_HTTP_DIR
;
}
conf
=
conf
->
get
(
"http"
);
if
(
!
conf
)
{
return
SRS_CONF_DEFAULT_HTTP_DIR
;
}
conf
=
conf
->
get
(
"dir"
);
if
(
!
conf
||
conf
->
arg0
().
empty
())
{
return
SRS_CONF_DEFAULT_HTTP_DIR
;
}
return
conf
->
arg0
();
}
bool
srs_directive_equals
(
SrsConfDirective
*
a
,
SrsConfDirective
*
b
)
...
...
trunk/src/app/srs_app_config.hpp
查看文件 @
83f35d1
...
...
@@ -56,6 +56,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// the interval in seconds for bandwidth check
#define SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS 1000
#define SRS_CONF_DEFAULT_HTTP_MOUNT "/"
#define SRS_CONF_DEFAULT_HTTP_DIR SRS_CONF_DEFAULT_HLS_PATH
#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
...
...
@@ -86,6 +89,8 @@ public:
enum
SrsDirectiveType
{
parse_file
,
parse_block
};
virtual
int
parse_conf
(
SrsFileBuffer
*
buffer
,
SrsDirectiveType
type
);
virtual
int
read_token
(
SrsFileBuffer
*
buffer
,
std
::
vector
<
std
::
string
>&
args
);
public
:
virtual
bool
is_vhost
();
};
/**
...
...
@@ -118,6 +123,7 @@ private:
virtual
void
print_help
(
char
**
argv
);
// global section
public:
virtual
SrsConfDirective
*
get_root
();
virtual
bool
get_deamon
();
virtual
int
get_max_connections
();
virtual
SrsConfDirective
*
get_listen
();
...
...
@@ -201,6 +207,10 @@ private:
public
:
virtual
bool
get_http_stream_enabled
();
virtual
int
get_http_stream_listen
();
public
:
virtual
bool
get_vhost_http_enabled
(
std
::
string
vhost
);
virtual
std
::
string
get_vhost_http_mount
(
std
::
string
vhost
);
virtual
std
::
string
get_vhost_http_dir
(
std
::
string
vhost
);
};
/**
...
...
trunk/src/app/srs_app_http.cpp
查看文件 @
83f35d1
...
...
@@ -325,8 +325,7 @@ SrsHttpHandler* SrsHttpHandler::create_http_api()
SrsHttpHandler
*
SrsHttpHandler
::
create_http_stream
()
{
// TODO: FIXME: use http stream handler instead.
return
new
SrsHttpHandler
();
return
new
SrsHttpRoot
();
}
SrsHttpMessage
::
SrsHttpMessage
()
...
...
trunk/src/app/srs_app_http_conn.cpp
查看文件 @
83f35d1
...
...
@@ -32,16 +32,151 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_app_socket.hpp>
#include <srs_app_http.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_core_autofree.hpp>
#include <srs_app_json.hpp>
#include <srs_app_config.hpp>
#define SRS_HTTP_HEADER_BUFFER 1024
SrsHttpRoot
::
SrsHttpRoot
()
{
// TODO: FIXME: support reload vhosts.
}
SrsHttpRoot
::~
SrsHttpRoot
()
{
}
int
SrsHttpRoot
::
initialize
()
{
int
ret
=
ERROR_SUCCESS
;
SrsConfDirective
*
root
=
_srs_config
->
get_root
();
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
!
conf
->
is_vhost
())
{
continue
;
}
std
::
string
vhost
=
conf
->
arg0
();
if
(
!
_srs_config
->
get_vhost_http_enabled
(
vhost
))
{
continue
;
}
std
::
string
mount
=
_srs_config
->
get_vhost_http_mount
(
vhost
);
std
::
string
dir
=
_srs_config
->
get_vhost_http_dir
(
vhost
);
handlers
.
push_back
(
new
SrsHttpVhost
(
vhost
,
mount
,
dir
));
}
return
ret
;
}
bool
SrsHttpRoot
::
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
)
{
if
(
!
SrsHttpHandler
::
is_handler_valid
(
req
,
status_code
,
reason_phrase
))
{
return
false
;
}
if
(
req
->
match
()
->
matched_url
.
length
()
!=
1
)
{
status_code
=
HTTP_NotFound
;
reason_phrase
=
HTTP_NotFound_str
;
return
false
;
}
return
true
;
}
bool
SrsHttpRoot
::
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
pchild
)
{
// reset the child path to path,
// for child to reparse the path.
*
pchild
=
path
;
// only compare the first char.
return
srs_path_equals
(
"/"
,
path
,
1
);
}
int
SrsHttpRoot
::
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
std
::
stringstream
ss
;
ss
<<
JOBJECT_START
<<
JFIELD_ERROR
(
ERROR_SUCCESS
)
<<
JFIELD_CONT
<<
JFIELD_ORG
(
"urls"
,
JOBJECT_START
);
vector
<
SrsHttpHandler
*>::
iterator
it
;
for
(
it
=
handlers
.
begin
();
it
!=
handlers
.
end
();
++
it
)
{
SrsHttpVhost
*
handler
=
dynamic_cast
<
SrsHttpVhost
*>
(
*
it
);
srs_assert
(
handler
);
ss
<<
JFIELD_ORG
(
handler
->
mount
(),
JOBJECT_START
)
<<
JFIELD_STR
(
"mount"
,
handler
->
mount
())
<<
JFIELD_CONT
<<
JFIELD_STR
(
"vhost"
,
handler
->
vhost
())
<<
JFIELD_CONT
<<
JFIELD_STR
(
"dir"
,
handler
->
dir
())
<<
JOBJECT_END
;
if
(
it
+
1
!=
handlers
.
end
())
{
ss
<<
JFIELD_CONT
;
}
}
ss
<<
JOBJECT_END
<<
JOBJECT_END
;
return
res_json
(
skt
,
req
,
ss
.
str
());
}
SrsHttpVhost
::
SrsHttpVhost
(
std
::
string
vhost
,
std
::
string
mount
,
std
::
string
dir
)
{
_vhost
=
vhost
;
_mount
=
mount
;
_dir
=
dir
;
}
SrsHttpVhost
::~
SrsHttpVhost
()
{
}
bool
SrsHttpVhost
::
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
/*pchild*/
)
{
return
srs_path_equals
(
"/api"
,
path
,
length
);
}
int
SrsHttpVhost
::
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
std
::
stringstream
ss
;
ss
<<
JOBJECT_START
<<
JFIELD_ERROR
(
ERROR_SUCCESS
)
<<
JFIELD_CONT
<<
JFIELD_ORG
(
"urls"
,
JOBJECT_START
)
<<
JFIELD_STR
(
"v1"
,
"the api version 1.0"
)
<<
JOBJECT_END
<<
JOBJECT_END
;
return
res_json
(
skt
,
req
,
ss
.
str
());
}
string
SrsHttpVhost
::
vhost
()
{
return
_vhost
;
}
string
SrsHttpVhost
::
mount
()
{
return
_mount
;
}
string
SrsHttpVhost
::
dir
()
{
return
_dir
;
}
SrsHttpConn
::
SrsHttpConn
(
SrsServer
*
srs_server
,
st_netfd_t
client_stfd
,
SrsHttpHandler
*
_handler
)
:
SrsConnection
(
srs_server
,
client_stfd
)
{
parser
=
new
SrsHttpParser
();
handler
=
_handler
;
requires_crossdomain
=
false
;
}
SrsHttpConn
::~
SrsHttpConn
()
...
...
@@ -96,34 +231,41 @@ int SrsHttpConn::do_cycle()
int
SrsHttpConn
::
process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
)
{
int
ret
=
ERROR_SUCCESS
;
// parse uri to schema/server:port/path?query
if
((
ret
=
req
->
parse_uri
())
!=
ERROR_SUCCESS
)
{
return
ret
;
}
if
(
req
->
method
()
==
HTTP_OPTIONS
)
{
char
data
[]
=
"HTTP/1.1 200 OK"
__CRLF
"Content-Length: 0"
__CRLF
"Server: SRS/"
RTMP_SIG_SRS_VERSION
""
__CRLF
"Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT"
__CRLF
"Access-Control-Allow-Origin: *"
__CRLF
"Access-Control-Allow-Methods: GET, POST, HEAD, PUT, DELETE"
__CRLF
"Access-Control-Allow-Headers: Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type"
__CRLF
"Content-Type: text/html;charset=utf-8"
__CRLFCRLF
""
;
return
skt
->
write
(
data
,
sizeof
(
data
),
NULL
);
}
else
{
std
::
string
tilte
=
"SRS/"
RTMP_SIG_SRS_VERSION
;
tilte
+=
" hello http/1.1 server~
\n
"
;
std
::
stringstream
ss
;
ss
<<
"HTTP/1.1 200 OK "
<<
__CRLF
<<
"Content-Length: "
<<
tilte
.
length
()
+
req
->
body_size
()
<<
__CRLF
<<
"Server: SRS/"
RTMP_SIG_SRS_VERSION
""
<<
__CRLF
<<
"Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT"
<<
__CRLF
<<
"Access-Control-Allow-Origin: *"
<<
__CRLF
<<
"Access-Control-Allow-Methods: GET, POST, HEAD, PUT, DELETE"
<<
__CRLF
<<
"Access-Control-Allow-Headers: Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type"
<<
__CRLF
<<
"Content-Type: text/html;charset=utf-8"
<<
__CRLFCRLF
<<
tilte
<<
req
->
body
().
c_str
()
<<
""
;
return
skt
->
write
(
ss
.
str
().
c_str
(),
ss
.
str
().
length
(),
NULL
);
srs_trace
(
"http request parsed, method=%d, url=%s, content-length=%"
PRId64
""
,
req
->
method
(),
req
->
url
().
c_str
(),
req
->
content_length
());
// TODO: maybe need to parse the url.
std
::
string
url
=
req
->
path
();
SrsHttpHandlerMatch
*
p
=
NULL
;
if
((
ret
=
handler
->
best_match
(
url
.
data
(),
url
.
length
(),
&
p
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"failed to find the best match handler for url. ret=%d"
,
ret
);
return
ret
;
}
// if success, p and pstart should be valid.
srs_assert
(
p
);
srs_assert
(
p
->
handler
);
srs_assert
(
p
->
matched_url
.
length
()
<=
url
.
length
());
srs_info
(
"best match handler, matched_url=%s"
,
p
->
matched_url
.
c_str
());
req
->
set_match
(
p
);
req
->
set_requires_crossdomain
(
requires_crossdomain
);
// use handler to process request.
if
((
ret
=
p
->
handler
->
process_request
(
skt
,
req
))
!=
ERROR_SUCCESS
)
{
srs_warn
(
"handler failed to process http request. ret=%d"
,
ret
);
return
ret
;
}
if
(
req
->
requires_crossdomain
())
{
requires_crossdomain
=
true
;
}
return
ret
;
...
...
trunk/src/app/srs_app_http_conn.hpp
查看文件 @
83f35d1
...
...
@@ -34,19 +34,50 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_app_st.hpp>
#include <srs_app_conn.hpp>
#include <http_parser.h>
#include <srs_app_http.hpp>
class
SrsSocket
;
class
SrsHttpParser
;
class
SrsHttpMessage
;
class
SrsHttpHandler
;
// for http root.
class
SrsHttpRoot
:
public
SrsHttpHandler
{
public
:
SrsHttpRoot
();
virtual
~
SrsHttpRoot
();
public
:
virtual
int
initialize
();
virtual
bool
is_handler_valid
(
SrsHttpMessage
*
req
,
int
&
status_code
,
std
::
string
&
reason_phrase
);
virtual
bool
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
pchild
);
virtual
int
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
);
};
class
SrsHttpVhost
:
public
SrsHttpHandler
{
private
:
std
::
string
_vhost
;
std
::
string
_mount
;
std
::
string
_dir
;
public
:
SrsHttpVhost
(
std
::
string
vhost
,
std
::
string
mount
,
std
::
string
dir
);
virtual
~
SrsHttpVhost
();
public
:
virtual
bool
can_handle
(
const
char
*
path
,
int
length
,
const
char
**
pchild
);
virtual
int
do_process_request
(
SrsSocket
*
skt
,
SrsHttpMessage
*
req
);
public
:
virtual
std
::
string
vhost
();
virtual
std
::
string
mount
();
virtual
std
::
string
dir
();
};
class
SrsHttpConn
:
public
SrsConnection
{
private
:
SrsHttpParser
*
parser
;
SrsHttpHandler
*
handler
;
bool
requires_crossdomain
;
public
:
SrsHttpConn
(
SrsServer
*
srs_server
,
st_netfd_t
client_stfd
,
SrsHttpHandler
*
_handler
);
virtual
~
SrsHttpConn
();
...
...
trunk/src/app/srs_app_json.hpp
查看文件 @
83f35d1
...
...
@@ -36,5 +36,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret
#define JFIELD_CONT ","
#define JOBJECT_END "}"
#define JARRAY_START "["
#define JARRAY_END "]"
#endif
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论