Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Moecube Store
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Moecube Store
Commits
89ea4df0
Commit
89ea4df0
authored
Jan 26, 2013
by
神楽坂玲奈
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server filter
parent
7d606ddb
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1169 additions
and
101 deletions
+1169
-101
assets/javascripts/rooms.coffee
assets/javascripts/rooms.coffee
+53
-22
assets/javascripts/rooms.js
assets/javascripts/rooms.js
+79
-45
assets/stylesheets/rooms.less
assets/stylesheets/rooms.less
+10
-0
rooms/index.html
rooms/index.html
+28
-34
vendor/javascripts/jquery.multiselect.min.js
vendor/javascripts/jquery.multiselect.min.js
+725
-0
vendor/stylesheets/jquery.multiselect.css
vendor/stylesheets/jquery.multiselect.css
+23
-0
vendor/stylesheets/mod_websocket.lua
vendor/stylesheets/mod_websocket.lua
+251
-0
No files found.
assets/javascripts/rooms.coffee
View file @
89ea4df0
...
...
@@ -3,6 +3,38 @@ class Server extends Spine.Model
@
extend
Spine
.
Model
.
Ajax
@
url
:
"/servers.json"
class
Servers
extends
Spine
.
Controller
constructor
:
->
super
Server
.
bind
"refresh"
,
@
render
Server
.
one
"refresh"
,
@
connect
render
:
=>
@
html
$
(
'#server_template'
).
tmpl
Server
.
all
()
@
el
.
multiselect
(
noneSelectedText
:
'房间筛选'
selectedText
:
'房间筛选'
header
:
false
minWidth
:
'auto'
classes
:
'server_filter'
).
bind
"multiselectclick"
,
(
event
,
ui
)
->
Room
.
trigger
'refresh'
connect
:
=>
wsServer
=
'ws://mycard-server.my-card.in:9998'
websocket
=
new
WebSocket
(
wsServer
);
websocket
.
onopen
=
->
console
.
log
(
"websocket: Connected to WebSocket server."
)
websocket
.
onclose
=
->
console
.
log
(
"websocket: Disconnected"
);
websocket
.
onmessage
=
(
evt
)
->
#console.log('Retrieved data from server: ' + evt.data)
rooms
=
JSON
.
parse
(
evt
.
data
)
for
room
in
rooms
if
room
.
_deleted
Room
.
find
(
room
.
id
).
destroy
()
if
Room
.
exists
(
room
.
id
)
Room
.
refresh
(
room
for
room
in
rooms
when
!
room
.
_deleted
)
websocket
.
onerror
=
(
evt
)
->
console
.
log
(
'websocket: Error occured: '
+
evt
.
data
);
class
Room
extends
Spine
.
Model
@
configure
"Room"
,
"name"
,
"status"
,
"private"
,
"rule"
,
"mode"
,
"start_lp"
@
belongsTo
'server'
,
Server
...
...
@@ -14,7 +46,11 @@ class Rooms extends Spine.Controller
super
Room
.
bind
"refresh"
,
@
render
render
:
=>
@
html
$
(
'#room_template'
).
tmpl
_
.
sortBy
Room
.
all
(),
@
sort
@
html
$
(
'#room_template'
).
tmpl
_
.
sortBy
(
_
.
filter
(
Room
.
all
(),
@
filter
),
@
sort
)
filter
:
(
room
)
->
_
.
find
$
(
'#servers'
).
multiselect
(
'getChecked'
),
(
e
)
->
parseInt
(
e
.
value
)
==
room
.
server_id
sort
:
(
room
)
->
[
if
room
.
status
==
"wait"
then
0
else
1
,
...
...
@@ -30,6 +66,17 @@ class Rooms extends Spine.Controller
mycard
.
join
(
room
.
server
().
ip
,
room
.
server
().
port
,
mycard
.
room_name
(
room
.
name
,
null
,
room
.
pvp
,
room
.
rule
,
room
.
mode
,
room
.
start_lp
))
login
=
(
username
,
password
)
->
#Candy.Core.Event.Jabber.Presence = (msg)->
# Candy.Core.log('[Jabber] Presence');
# msg = $(msg);
# if(msg.children('x[xmlns^="' + Strophe.NS.MUC + '"]').length > 0)
# if (msg.attr('type') == 'error')
# self.Jabber.Room.PresenceError(msg);
# else
# self.Jabber.Room.Presence(msg);
# else
# alert msg
# true
Candy
.
init
(
'http://s70.hebexpo.com:5280/http-bind/'
,
core
:
debug
:
false
,
...
...
@@ -116,10 +163,10 @@ $(document).ready ->
#$('#login_domain').combobox()
$
(
'#login_dialog'
).
dialog
autoOpen
:
false
,
resizable
:
false
,
title
:
"用户登录"
#
$('#login_dialog').dialog
#
autoOpen:false,
#
resizable:false,
#
title:"用户登录"
$
(
'#login_button'
).
click
->
login
()
...
...
@@ -132,23 +179,7 @@ $(document).ready ->
# false
rooms
=
new
Rooms
(
el
:
$
(
'#rooms'
))
Server
.
one
"refresh"
,
->
wsServer
=
'ws://mycard-server.my-card.in:9998'
websocket
=
new
WebSocket
(
wsServer
);
websocket
.
onopen
=
->
console
.
log
(
"Connected to WebSocket server."
)
websocket
.
onclose
=
->
console
.
log
(
"Disconnected"
);
websocket
.
onmessage
=
(
evt
)
->
console
.
log
(
'Retrieved data from server: '
+
evt
.
data
)
rooms
=
JSON
.
parse
(
evt
.
data
)
for
room
in
rooms
if
room
.
_deleted
Room
.
find
(
room
.
id
).
destroy
()
if
Room
.
exists
(
room
.
id
)
Room
.
refresh
(
room
for
room
in
rooms
when
!
room
.
_deleted
)
websocket
.
onerror
=
(
evt
)
->
console
.
log
(
'Error occured: '
+
evt
.
data
);
servers
=
new
Servers
(
el
:
$
(
'#servers'
))
Server
.
fetch
()
assets/javascripts/rooms.js
View file @
89ea4df0
// Generated by CoffeeScript 1.4.0
(
function
()
{
var
Room
,
Rooms
,
Server
,
login
,
var
Room
,
Rooms
,
Server
,
Servers
,
login
,
__hasProp
=
{}.
hasOwnProperty
,
__extends
=
function
(
child
,
parent
)
{
for
(
var
key
in
parent
)
{
if
(
__hasProp
.
call
(
parent
,
key
))
child
[
key
]
=
parent
[
key
];
}
function
ctor
()
{
this
.
constructor
=
child
;
}
ctor
.
prototype
=
parent
.
prototype
;
child
.
prototype
=
new
ctor
();
child
.
__super__
=
parent
.
prototype
;
return
child
;
},
__bind
=
function
(
fn
,
me
){
return
function
(){
return
fn
.
apply
(
me
,
arguments
);
};
};
...
...
@@ -23,6 +23,74 @@
})(
Spine
.
Model
);
Servers
=
(
function
(
_super
)
{
__extends
(
Servers
,
_super
);
function
Servers
()
{
this
.
connect
=
__bind
(
this
.
connect
,
this
);
this
.
render
=
__bind
(
this
.
render
,
this
);
Servers
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
Server
.
bind
(
"
refresh
"
,
this
.
render
);
Server
.
one
(
"
refresh
"
,
this
.
connect
);
}
Servers
.
prototype
.
render
=
function
()
{
this
.
html
(
$
(
'
#server_template
'
).
tmpl
(
Server
.
all
()));
return
this
.
el
.
multiselect
({
noneSelectedText
:
'
房间筛选
'
,
selectedText
:
'
房间筛选
'
,
header
:
false
,
minWidth
:
'
auto
'
,
classes
:
'
server_filter
'
}).
bind
(
"
multiselectclick
"
,
function
(
event
,
ui
)
{
return
Room
.
trigger
(
'
refresh
'
);
});
};
Servers
.
prototype
.
connect
=
function
()
{
var
websocket
,
wsServer
;
wsServer
=
'
ws://mycard-server.my-card.in:9998
'
;
websocket
=
new
WebSocket
(
wsServer
);
websocket
.
onopen
=
function
()
{
return
console
.
log
(
"
websocket: Connected to WebSocket server.
"
);
};
websocket
.
onclose
=
function
()
{
return
console
.
log
(
"
websocket: Disconnected
"
);
};
websocket
.
onmessage
=
function
(
evt
)
{
var
room
,
rooms
,
_i
,
_len
;
rooms
=
JSON
.
parse
(
evt
.
data
);
for
(
_i
=
0
,
_len
=
rooms
.
length
;
_i
<
_len
;
_i
++
)
{
room
=
rooms
[
_i
];
if
(
room
.
_deleted
)
{
if
(
Room
.
exists
(
room
.
id
))
{
Room
.
find
(
room
.
id
).
destroy
();
}
}
}
return
Room
.
refresh
((
function
()
{
var
_j
,
_len1
,
_results
;
_results
=
[];
for
(
_j
=
0
,
_len1
=
rooms
.
length
;
_j
<
_len1
;
_j
++
)
{
room
=
rooms
[
_j
];
if
(
!
room
.
_deleted
)
{
_results
.
push
(
room
);
}
}
return
_results
;
})());
};
return
websocket
.
onerror
=
function
(
evt
)
{
return
console
.
log
(
'
websocket: Error occured:
'
+
evt
.
data
);
};
};
return
Servers
;
})(
Spine
.
Controller
);
Room
=
(
function
(
_super
)
{
__extends
(
Room
,
_super
);
...
...
@@ -54,7 +122,13 @@
}
Rooms
.
prototype
.
render
=
function
()
{
return
this
.
html
(
$
(
'
#room_template
'
).
tmpl
(
_
.
sortBy
(
Room
.
all
(),
this
.
sort
)));
return
this
.
html
(
$
(
'
#room_template
'
).
tmpl
(
_
.
sortBy
(
_
.
filter
(
Room
.
all
(),
this
.
filter
),
this
.
sort
)));
};
Rooms
.
prototype
.
filter
=
function
(
room
)
{
return
_
.
find
(
$
(
'
#servers
'
).
multiselect
(
'
getChecked
'
),
function
(
e
)
{
return
parseInt
(
e
.
value
)
===
room
.
server_id
;
});
};
Rooms
.
prototype
.
sort
=
function
(
room
)
{
...
...
@@ -113,7 +187,7 @@
};
$
(
document
).
ready
(
function
()
{
var
jid
,
new_room
,
rooms
;
var
jid
,
new_room
,
rooms
,
servers
;
if
(
jid
=
Candy
.
Util
.
getCookie
(
'
jid
'
))
{
login
(
jid
,
Candy
.
Util
.
getCookie
(
'
password
'
));
}
...
...
@@ -179,54 +253,14 @@
new_room
.
name
.
value
=
Math
.
floor
(
Math
.
random
()
*
1000
);
return
$
(
'
#new_room_dialog
'
).
dialog
(
'
open
'
);
});
$
(
'
#login_dialog
'
).
dialog
({
autoOpen
:
false
,
resizable
:
false
,
title
:
"
用户登录
"
});
$
(
'
#login_button
'
).
click
(
function
()
{
return
login
();
});
rooms
=
new
Rooms
({
el
:
$
(
'
#rooms
'
)
});
Server
.
one
(
"
refresh
"
,
function
()
{
var
websocket
,
wsServer
;
wsServer
=
'
ws://mycard-server.my-card.in:9998
'
;
websocket
=
new
WebSocket
(
wsServer
);
websocket
.
onopen
=
function
()
{
return
console
.
log
(
"
Connected to WebSocket server.
"
);
};
websocket
.
onclose
=
function
()
{
return
console
.
log
(
"
Disconnected
"
);
};
websocket
.
onmessage
=
function
(
evt
)
{
var
room
,
_i
,
_len
;
console
.
log
(
'
Retrieved data from server:
'
+
evt
.
data
);
rooms
=
JSON
.
parse
(
evt
.
data
);
for
(
_i
=
0
,
_len
=
rooms
.
length
;
_i
<
_len
;
_i
++
)
{
room
=
rooms
[
_i
];
if
(
room
.
_deleted
)
{
if
(
Room
.
exists
(
room
.
id
))
{
Room
.
find
(
room
.
id
).
destroy
();
}
}
}
return
Room
.
refresh
((
function
()
{
var
_j
,
_len1
,
_results
;
_results
=
[];
for
(
_j
=
0
,
_len1
=
rooms
.
length
;
_j
<
_len1
;
_j
++
)
{
room
=
rooms
[
_j
];
if
(
!
room
.
_deleted
)
{
_results
.
push
(
room
);
}
}
return
_results
;
})());
};
return
websocket
.
onerror
=
function
(
evt
)
{
return
console
.
log
(
'
Error occured:
'
+
evt
.
data
);
};
servers
=
new
Servers
({
el
:
$
(
'
#servers
'
)
});
return
Server
.
fetch
();
});
...
...
assets/stylesheets/rooms.less
View file @
89ea4df0
...
...
@@ -77,4 +77,14 @@ body{background:#fbfbfb;}
#domain{
width: 74px;
}
}
.server_filter label{
font-size: 12px;
}
.ui-widget.server_filter{
font-size: 100%;
.ui-multiselect-checkboxes{
overflow-y: visible
}
}
\ No newline at end of file
rooms/index.html
View file @
89ea4df0
...
...
@@ -42,6 +42,23 @@
})();
</script>
<script
id=
"login_form_template"
type=
"text/x-mustache-template"
>
<
form
method
=
"
post
"
id
=
"
login-form
"
class
=
"
login-form
"
onsubmit
=
"
{{#displayUsername}}username.value = node.value + '@' + domain.value;{{/displayUsername}}Candy.Util.setCookie('jid', username.value, 365);Candy.Util.setCookie('username', node.value, 365);Candy.Util.setCookie('password', password.value, 365)
"
>
{{
#
displayUsername
}}
<
label
for
=
"
node
"
>
{{
_labelUsername
}}
<
/label
>
<
input
type
=
"
text
"
id
=
"
node
"
name
=
"
node
"
/>
<
label
for
=
"
domain
"
>
@
<
/label
>
<
select
id
=
"
domain
"
name
=
"
domain
"
tabindex
=
"
-1
"
>
<
option
label
=
"
my-card.in
"
value
=
"
my-card.in
"
selected
=
"
selected
"
/>
<
option
label
=
"
gmail.com
"
value
=
"
gmail.com
"
/>
<
/select
>
{{
/
displayUsername
}}
<
input
type
=
"
hidden
"
id
=
"
username
"
name
=
"
username
"
value
=
"
{{presetJid}}
"
/>
{{
#
displayPassword
}}
<
label
for
=
"
password
"
>
{{
_labelPassword
}}
<
/label><input type="password" id="password" name="password" /
>
{{
/
displayPassword
}}
<
input
type
=
"
submit
"
class
=
"
button
"
value
=
"
{{_loginSubmit}}
"
/>
<
/form
>
</script>
<script
id=
"room_template"
type=
"text/x-jquery-tmpl"
>
<
div
class
=
"
room
"
id
=
"
room_${id}
"
>
...
...
@@ -59,24 +76,11 @@
<
/div
>
<
/div
>
</script>
<script
id=
"server_template"
type=
"text/x-jquery-tmpl"
>
<
option
value
=
"
${id}
"
selected
=
"
selected
"
>
$
{
name
}
<
/option
>
</script>
<script
id=
"login_form_template"
type=
"text/x-mustache-template"
>
<
form
method
=
"
post
"
id
=
"
login-form
"
class
=
"
login-form
"
onsubmit
=
"
{{#displayUsername}}username.value = node.value + '@' + domain.value;{{/displayUsername}}Candy.Util.setCookie('jid', username.value, 365);Candy.Util.setCookie('username', node.value, 365);Candy.Util.setCookie('password', password.value, 365)
"
>
{{
#
displayUsername
}}
<
label
for
=
"
node
"
>
{{
_labelUsername
}}
<
/label
>
<
input
type
=
"
text
"
id
=
"
node
"
name
=
"
node
"
/>
<
label
for
=
"
domain
"
>
@
<
/label
>
<
select
id
=
"
domain
"
name
=
"
domain
"
tabindex
=
"
-1
"
>
<
option
label
=
"
my-card.in
"
value
=
"
my-card.in
"
selected
=
"
selected
"
/>
<
option
label
=
"
gmail.com
"
value
=
"
gmail.com
"
/>
<
/select
>
{{
/
displayUsername
}}
<
input
type
=
"
hidden
"
id
=
"
username
"
name
=
"
username
"
value
=
"
{{presetJid}}
"
/>
{{
#
displayPassword
}}
<
label
for
=
"
password
"
>
{{
_labelPassword
}}
<
/label><input type="password" id="password" name="password" /
>
{{
/
displayPassword
}}
<
input
type
=
"
submit
"
class
=
"
button
"
value
=
"
{{_loginSubmit}}
"
/>
<
/form
>
</script>
</head>
<body>
<!--[if lt IE 7]>
...
...
@@ -91,11 +95,7 @@
<img
src=
"/assets/images/logo.png"
alt=
""
/>
</div>
<div
class=
"card_form"
>
<select
name=
""
id=
""
>
<option
value=
""
>
选择分区
</option>
<option
value=
""
></option>
<option
value=
""
></option>
</select>
<select
id=
"servers"
multiple=
"multiple"
></select>
<input
id=
"new_room_button"
type=
"button"
value=
"建立房间"
/>
</div>
<div
class=
"log_reg"
>
...
...
@@ -107,16 +107,16 @@
<div
class=
"card_center"
>
<div
id=
"rooms"
></div>
<div
class=
"online_list"
>
<div
class=
"online_title"
>
在线用户
</div>
<div
class=
"online_title"
>
好友
</div>
<ul>
<li>
<
img
src=
"/assets/images/hs1.jpg"
alt=
""
/><span>
Yolua Mesiade
</span>
<
span>
这是开发中好友系统喵
</span>
</li>
<li>
<
img
src=
"/assets/images/hs1.jpg"
alt=
""
/><span>
Yolua Mesiade
</span>
<
span>
看起来比较麻烦样子于是先坑几天
</span>
</li>
<li>
<
img
src=
"/assets/images/hs1.jpg"
alt=
""
/><span>
Yolua Mesiade
</span>
<
span>
下面留的是管理员
</span>
</li>
<li>
<img
src=
"/assets/images/hs1.jpg"
alt=
""
/><span>
Yolua Mesiade
</span>
...
...
@@ -227,7 +227,9 @@
<script
src=
"/vendor/javascripts/jquery-ui-1.10.0.custom.min.js"
></script>
<script
src=
"/vendor/javascripts/jquery.cookie.js"
></script>
<script
src=
"/vendor/javascripts/jquery.select.js"
></script>
<script
src=
"/assets/javascripts/jquery-ui.cambobox.js"
></script>
<script
src=
"/vendor/javascripts/jquery.multiselect.min.js"
></script>
<link
rel=
"stylesheet"
type=
"text/css"
href=
"/vendor/stylesheets/jquery.multiselect.css"
/>
<script
src=
"/vendor/javascripts/spine/spine.js"
></script>
<script
src=
"/vendor/javascripts/spine/ajax.js"
></script>
...
...
@@ -247,13 +249,5 @@
<link
rel=
"stylesheet"
type=
"text/css"
href=
"/vendor/candy/plugins/inline-images/candy.css"
/>
<script
src=
"/assets/javascripts/rooms.js"
></script>
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<!--<script>
var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>-->
</body>
</html>
vendor/javascripts/jquery.multiselect.min.js
0 → 100644
View file @
89ea4df0
This diff is collapsed.
Click to expand it.
vendor/stylesheets/jquery.multiselect.css
0 → 100644
View file @
89ea4df0
.ui-multiselect
{
padding
:
2px
0
2px
4px
;
text-align
:
left
}
.ui-multiselect
span
.ui-icon
{
float
:
right
}
.ui-multiselect-single
.ui-multiselect-checkboxes
input
{
position
:
absolute
!important
;
top
:
auto
!important
;
left
:
-9999px
;
}
.ui-multiselect-single
.ui-multiselect-checkboxes
label
{
padding
:
5px
!important
}
.ui-multiselect-header
{
margin-bottom
:
3px
;
padding
:
3px
0
3px
4px
}
.ui-multiselect-header
ul
{
font-size
:
0.9em
}
.ui-multiselect-header
ul
li
{
float
:
left
;
padding
:
0
10px
0
0
}
.ui-multiselect-header
a
{
text-decoration
:
none
}
.ui-multiselect-header
a
:hover
{
text-decoration
:
underline
}
.ui-multiselect-header
span
.ui-icon
{
float
:
left
}
.ui-multiselect-header
li
.ui-multiselect-close
{
float
:
right
;
text-align
:
right
;
padding-right
:
0
}
.ui-multiselect-menu
{
display
:
none
;
padding
:
3px
;
position
:
absolute
;
z-index
:
10000
;
text-align
:
left
}
.ui-multiselect-checkboxes
{
position
:
relative
/* fixes bug in IE6/7 */
;
overflow-y
:
scroll
}
.ui-multiselect-checkboxes
label
{
cursor
:
default
;
display
:
block
;
border
:
1px
solid
transparent
;
padding
:
3px
1px
}
.ui-multiselect-checkboxes
label
input
{
position
:
relative
;
top
:
1px
}
.ui-multiselect-checkboxes
li
{
clear
:
both
;
font-size
:
0.9em
;
padding-right
:
3px
}
.ui-multiselect-checkboxes
li
.ui-multiselect-optgroup-label
{
text-align
:
center
;
font-weight
:
bold
;
border-bottom
:
1px
solid
}
.ui-multiselect-checkboxes
li
.ui-multiselect-optgroup-label
a
{
display
:
block
;
padding
:
3px
;
margin
:
1px
0
;
text-decoration
:
none
}
/* remove label borders in IE6 because IE6 does not support transparency */
*
html
.ui-multiselect-checkboxes
label
{
border
:
none
}
vendor/stylesheets/mod_websocket.lua
0 → 100644
View file @
89ea4df0
-- Prosody IM
-- Copyright (C) 2012 Florian Zeitz
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
module
:
set_global
();
local
add_filter
=
require
"util.filters"
.
add_filter
;
local
sha1
=
require
"util.hashes"
.
sha1
;
local
base64
=
require
"util.encodings"
.
base64
.
encode
;
local
softreq
=
require
"util.dependencies"
.
softreq
;
local
portmanager
=
require
"core.portmanager"
;
local
bit
=
softreq
"bit"
or
softreq
"bit32"
or
module
:
log
(
"error"
,
"No bit module found. Either LuaJIT 2 or Lua 5.2 is required"
);
local
band
=
bit
.
band
;
local
bxor
=
bit
.
bxor
;
local
cross_domain
=
module
:
get_option
(
"cross_domain_websocket"
);
if
cross_domain
then
if
cross_domain
==
true
then
cross_domain
=
"*"
;
elseif
type
(
cross_domain
)
==
"table"
then
cross_domain
=
table.concat
(
cross_domain
,
", "
);
end
if
type
(
cross_domain
)
~=
"string"
then
cross_domain
=
nil
;
end
end
module
:
depends
(
"c2s"
)
local
sessions
=
module
:
shared
(
"c2s/sessions"
);
local
c2s_listener
=
portmanager
.
get_service
(
"c2s"
).
listener
;
-- Websocket helpers
local
function
parse_frame
(
frame
)
local
result
=
{};
local
pos
=
1
;
local
length_bytes
=
0
;
local
counter
=
0
;
local
tmp_byte
;
if
#
frame
<
2
then
return
;
end
tmp_byte
=
string.byte
(
frame
,
pos
);
result
.
FIN
=
band
(
tmp_byte
,
0x80
)
>
0
;
result
.
RSV1
=
band
(
tmp_byte
,
0x40
)
>
0
;
result
.
RSV2
=
band
(
tmp_byte
,
0x20
)
>
0
;
result
.
RSV3
=
band
(
tmp_byte
,
0x10
)
>
0
;
result
.
opcode
=
band
(
tmp_byte
,
0x0F
);
pos
=
pos
+
1
;
tmp_byte
=
string.byte
(
frame
,
pos
);
result
.
MASK
=
band
(
tmp_byte
,
0x80
)
>
0
;
result
.
length
=
band
(
tmp_byte
,
0x7F
);
if
result
.
length
==
126
then
length_bytes
=
2
;
result
.
length
=
0
;
elseif
result
.
length
==
127
then
length_bytes
=
8
;
result
.
length
=
0
;
end
if
#
frame
<
(
2
+
length_bytes
)
then
return
;
end
for
i
=
1
,
length_bytes
do
pos
=
pos
+
1
;
result
.
length
=
result
.
length
*
256
+
string.byte
(
frame
,
pos
);
end
if
#
frame
<
(
2
+
length_bytes
+
(
result
.
MASK
and
4
or
0
)
+
result
.
length
)
then
return
;
end
if
result
.
MASK
then
result
.
key
=
{
string.byte
(
frame
,
pos
+
1
),
string.byte
(
frame
,
pos
+
2
),
string.byte
(
frame
,
pos
+
3
),
string.byte
(
frame
,
pos
+
4
)}
pos
=
pos
+
5
;
result
.
data
=
""
;
for
i
=
pos
,
pos
+
result
.
length
-
1
do
result
.
data
=
result
.
data
..
string.char
(
bxor
(
result
.
key
[
counter
+
1
],
string.byte
(
frame
,
i
)));
counter
=
(
counter
+
1
)
%
4
;
end
else
result
.
data
=
frame
:
sub
(
pos
+
1
,
pos
+
result
.
length
);
end
return
result
,
2
+
length_bytes
+
(
result
.
MASK
and
4
or
0
)
+
result
.
length
;
end
local
function
build_frame
(
desc
)
local
length
;
local
result
=
""
;
local
data
=
desc
.
data
or
""
;
result
=
result
..
string.char
(
0x80
*
(
desc
.
FIN
and
1
or
0
)
+
desc
.
opcode
);
length
=
#
data
;
if
length
<=
125
then
-- 7-bit length
result
=
result
..
string.char
(
length
);
elseif
length
<=
0xFFFF
then
-- 2-byte length
result
=
result
..
string.char
(
126
);
result
=
result
..
string.char
(
length
/
0x100
)
..
string.char
(
length
%
0x100
);
else
-- 8-byte length
result
=
result
..
string.char
(
127
);
for
i
=
7
,
0
,
-
1
do
result
=
result
..
string.char
((
length
/
(
2
^
(
8
*
i
))
)
%
0x100
);
end
end
result
=
result
..
data
;
return
result
;
end
--- Filter stuff
function
handle_request
(
event
,
path
)
local
request
,
response
=
event
.
request
,
event
.
response
;
local
conn
=
response
.
conn
;
if
not
request
.
headers
.
sec_websocket_key
then
response
.
headers
.
content_type
=
"text/html"
;
return
[[<!DOCTYPE html><html><head><title>Websocket</title></head><body>
<p>It works! Now point your WebSocket client to this URL to connect to Prosody.</p>
</body></html>]]
;
end
local
wants_xmpp
=
false
;
(
request
.
headers
.
sec_websocket_protocol
or
""
):
gsub
(
"
([^
,
]
*
)
,
?
"
,
function
(
proto
)
if
proto
==
"xmpp"
then
wants_xmpp
=
true
;
end
end
);
if
not
wants_xmpp
then
return
501
;
end
local
function
websocket_close
(
code
,
message
)
local
data
=
string.char
(
code
/
0x100
)
..
string.char
(
code
%
0x100
)
..
message
;
conn
:
write
(
build_frame
({
opcode
=
0x8
,
FIN
=
true
,
data
=
data
}));
conn
:
close
();
end
local
dataBuffer
;
local
function
handle_frame
(
frame
)
module
:
log
(
"debug"
,
"Websocket received: %s (%i bytes)"
,
frame
.
data
,
#
frame
.
data
);
-- Error cases
if
frame
.
RSV1
or
frame
.
RSV2
or
frame
.
RSV3
then
-- Reserved bits non zero
websocket_close
(
1002
,
"Reserved bits not zero"
);
return
false
;
end
if
frame
.
opcode
>=
0x8
and
frame
.
length
>
125
then
-- Control frame with too much payload
websocket_close
(
1002
,
"Payload too large"
);
return
false
;
end
if
frame
.
opcode
>=
0x8
and
not
frame
.
FIN
then
-- Fragmented control frame
websocket_close
(
1002
,
"Fragmented control frame"
);
return
false
;
end
if
(
frame
.
opcode
>
0x2
and
frame
.
opcode
<
0x8
)
or
(
frame
.
opcode
>
0xA
)
then
websocket_close
(
1002
,
"Reserved opcode"
);
return
false
;
end
if
frame
.
opcode
==
0x0
and
not
dataBuffer
then
websocket_close
(
1002
,
"Unexpected continuation frame"
);
return
false
;
end
if
(
frame
.
opcode
==
0x1
or
frame
.
opcode
==
0x2
)
and
dataBuffer
then
websocket_close
(
1002
,
"Continuation frame expected"
);
return
false
;
end
-- Valid cases
if
frame
.
opcode
==
0x0
then
-- Continuation frame
dataBuffer
=
dataBuffer
..
frame
.
data
;
elseif
frame
.
opcode
==
0x1
then
-- Text frame
dataBuffer
=
frame
.
data
;
elseif
frame
.
opcode
==
0x2
then
-- Binary frame
websocket_close
(
1003
,
"Only text frames are supported"
);
return
;
elseif
frame
.
opcode
==
0x8
then
-- Close request
websocket_close
(
1000
,
"Goodbye"
);
return
;
elseif
frame
.
opcode
==
0x9
then
-- Ping frame
frame
.
opcode
=
0xA
;
conn
:
write
(
build_frame
(
frame
));
return
""
;
else
log
(
"warn"
,
"Received frame with unsupported opcode %i"
,
frame
.
opcode
);
return
""
;
end
if
frame
.
FIN
then
data
=
dataBuffer
;
dataBuffer
=
nil
;
return
data
;
end
return
""
;
end
conn
:
setlistener
(
c2s_listener
);
c2s_listener
.
onconnect
(
conn
);
local
frameBuffer
=
""
;
add_filter
(
sessions
[
conn
],
"bytes/in"
,
function
(
data
)
local
cache
=
""
;
frameBuffer
=
frameBuffer
..
data
;
local
frame
,
length
=
parse_frame
(
frameBuffer
);
while
frame
do
frameBuffer
=
frameBuffer
:
sub
(
length
+
1
);
local
result
=
handle_frame
(
frame
);
if
not
result
then
return
;
end
cache
=
cache
..
result
;
frame
,
length
=
parse_frame
(
frameBuffer
);
end
return
cache
;
end
);
add_filter
(
sessions
[
conn
],
"bytes/out"
,
function
(
data
)
return
build_frame
({
FIN
=
true
,
opcode
=
0x01
,
data
=
tostring
(
data
)});
end
);
response
.
status
=
"101 Switching Protocols"
;
response
.
headers
.
upgrade
=
"websocket"
;
response
.
headers
.
connection
=
"Upgrade"
;
response
.
headers
.
sec_webSocket_accept
=
base64
(
sha1
(
request
.
headers
.
sec_websocket_key
..
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
));
response
.
headers
.
sec_webSocket_protocol
=
"xmpp"
;
response
.
headers
.
access_control_allow_origin
=
cross_domain
;
return
""
;
end
function
module
.
add_host
(
module
)
module
:
depends
(
"http"
);
module
:
provides
(
"http"
,
{
name
=
"xmpp-websocket"
;
route
=
{
[
"GET"
]
=
handle_request
;
[
"GET /"
]
=
handle_request
;
};
});
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment