ki 0.4.10 → 0.4.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +16 -8
- data/MIDDLEWARE.md +27 -7
- data/README.md +45 -2
- data/REALTIME.md +48 -0
- data/TODO.md +19 -0
- data/ki.gemspec +1 -0
- data/lib/ki.rb +5 -0
- data/lib/ki/base_request.rb +7 -0
- data/lib/ki/channel_manager.rb +58 -0
- data/lib/ki/ki.rb +1 -0
- data/lib/ki/ki_cli.rb +1 -1
- data/lib/ki/ki_config.rb +18 -2
- data/lib/ki/middleware/api_handler.rb +11 -16
- data/lib/ki/middleware/helpers/redirect_to_helper.rb +13 -0
- data/lib/ki/middleware/realtime.rb +81 -0
- data/lib/ki/model.rb +6 -4
- data/lib/ki/modules/restrictions.rb +4 -7
- data/lib/ki/orm.rb +38 -2
- data/lib/ki/utils/redirect_to_helper.rb +0 -0
- data/lib/ki/version.rb +1 -1
- data/spec/examples/json.northpole.ro/.bowerrc +3 -0
- data/spec/examples/json.northpole.ro/Gemfile +1 -0
- data/spec/examples/json.northpole.ro/bower.json +17 -0
- data/spec/examples/json.northpole.ro/config.ru +3 -0
- data/spec/examples/json.northpole.ro/config.yml +4 -0
- data/spec/examples/json.northpole.ro/config.yml.backup +18 -0
- data/spec/examples/json.northpole.ro/config/deploy.rb +2 -1
- data/spec/examples/json.northpole.ro/config/deploy/production.rb +4 -38
- data/spec/examples/json.northpole.ro/public/app/.bowerrc +3 -0
- data/spec/examples/json.northpole.ro/public/app/.gitignore +9 -0
- data/spec/examples/json.northpole.ro/public/app/.jshintrc +13 -0
- data/spec/examples/json.northpole.ro/public/app/.travis.yml +14 -0
- data/spec/examples/json.northpole.ro/public/app/LICENSE +22 -0
- data/spec/examples/json.northpole.ro/public/app/README.md +82 -0
- data/spec/examples/json.northpole.ro/public/app/bower.json +20 -0
- data/spec/examples/json.northpole.ro/public/app/e2e/pages/ContactUser.js +22 -0
- data/spec/examples/json.northpole.ro/public/app/e2e/pages/UserDetails.js +11 -0
- data/spec/examples/json.northpole.ro/public/app/e2e/pages/UserList.js +12 -0
- data/spec/examples/json.northpole.ro/public/app/e2e/protractor.conf.js +26 -0
- data/spec/examples/json.northpole.ro/public/app/e2e/scenarios/users.js +34 -0
- data/spec/examples/json.northpole.ro/public/app/gulpfile.js +104 -0
- data/spec/examples/json.northpole.ro/public/app/karma.conf.js +35 -0
- data/spec/examples/json.northpole.ro/public/app/package.json +30 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatar-1.svg +11 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatar-4.svg +16 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/avatars.svg +244 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/google_plus.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/hangouts.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_fullscreen_48px.svg +4 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_fullscreen_exit_48px.svg +4 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_music_note_48px.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_note_add_48px.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/ic_view_list_48px.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/icon.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/mail.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/manggo.svg +1095 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/menu.svg +4 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/phone.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/share.svg +3 -0
- data/spec/examples/json.northpole.ro/public/app/src/assets/svg/twitter.svg +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/css/app.css +138 -0
- data/spec/examples/json.northpole.ro/public/app/src/css/app.css.map +7 -0
- data/spec/examples/json.northpole.ro/public/app/src/css/app.sass +145 -0
- data/spec/examples/json.northpole.ro/public/app/src/index.html +157 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/MainController.coffee +167 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/app.coffee +58 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/blobs/BlobsController.coffee +115 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/blobs/blobs.html +48 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/tutorial/tutorial.html +15 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/users/UserService.coffee +12 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/users/Users.coffee +1 -0
- data/spec/examples/json.northpole.ro/public/app/src/js/users/users.html +8 -0
- data/spec/examples/json.northpole.ro/public/javascripts/jnorthpole.coffee +40 -7
- data/spec/examples/json.northpole.ro/public/javascripts/realtime.coffee +28 -0
- data/spec/examples/json.northpole.ro/public/{javascripts/music → music}/angular-youtube-embed.js +0 -0
- data/spec/examples/json.northpole.ro/public/music/index.html +126 -0
- data/spec/examples/json.northpole.ro/public/music/music.coffee +99 -0
- data/spec/examples/json.northpole.ro/public/music/music.sass +63 -0
- data/spec/examples/json.northpole.ro/public/stylesheets/app.sass +3 -0
- data/spec/examples/json.northpole.ro/views/faq.haml +7 -0
- data/spec/examples/json.northpole.ro/views/layout.haml +1 -0
- data/spec/examples/json.northpole.ro/views/music.haml +2 -0
- data/spec/examples/json.northpole.ro/views/websocket.haml +7 -0
- data/spec/lib/ki/channel_manager_spec.rb +82 -0
- data/spec/lib/ki/helpers_spec.rb +11 -0
- data/spec/lib/ki/ki_config_spec.rb +28 -0
- data/spec/lib/ki/middleware/admin_generator_spec.rb +8 -0
- data/spec/lib/ki/middleware/init_middleware_spec.rb +21 -0
- data/spec/lib/ki/middleware/realtime_spec.rb +96 -0
- data/spec/lib/ki/model_spec.rb +28 -7
- data/spec/lib/ki/modules/model_helper_spec.rb +31 -0
- data/spec/lib/ki/orm_spec.rb +26 -0
- metadata +211 -9
- data/spec/examples/json.northpole.ro/public/javascripts/docs.min.js +0 -16
- data/spec/examples/json.northpole.ro/views/awsum.haml +0 -108
@@ -0,0 +1,28 @@
|
|
1
|
+
$(document).ready ->
|
2
|
+
receivedMessages = []
|
3
|
+
|
4
|
+
output = $('.realtime-output')
|
5
|
+
return if output.length <= 0
|
6
|
+
|
7
|
+
socket = jNorthPole.getNewRealtimeSocket((data) ->
|
8
|
+
console.log data
|
9
|
+
return unless data.data?
|
10
|
+
json = JSON.parse(data.data)
|
11
|
+
return unless json.messages?
|
12
|
+
|
13
|
+
for message in json.messages
|
14
|
+
if $.inArray(message.id, receivedMessages) == -1
|
15
|
+
receivedMessages.push(message.id)
|
16
|
+
output.append("#{message.content.message}<br />")
|
17
|
+
)
|
18
|
+
setTimeout ->
|
19
|
+
jNorthPole.subscribe(socket, 'jNorthPoleChat')
|
20
|
+
, 2000
|
21
|
+
|
22
|
+
$('.realtime-input').keypress((event) ->
|
23
|
+
keycode = if event.keyCode then event.keyCode else event.which
|
24
|
+
if (keycode == 13)
|
25
|
+
inptz = $(@)
|
26
|
+
jNorthPole.publish(socket, 'jNorthPoleChat', { message: inptz.val() })
|
27
|
+
inptz.val('')
|
28
|
+
)
|
data/spec/examples/json.northpole.ro/public/{javascripts/music → music}/angular-youtube-embed.js
RENAMED
File without changes
|
@@ -0,0 +1,126 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html ng-app="app">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width">
|
6
|
+
<title>music</title>
|
7
|
+
|
8
|
+
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
|
9
|
+
<!-- Include roboto.css to use the Roboto web font, material.css to include the theme and ripples.css to style the ripple effect -->
|
10
|
+
<link href="/bootstrap-material-design/dist/css/roboto.min.css" rel="stylesheet">
|
11
|
+
<link href="/bootstrap-material-design/dist/css/material.min.css" rel="stylesheet">
|
12
|
+
<link href="/bootstrap-material-design/dist/css/ripples.min.css" rel="stylesheet">
|
13
|
+
|
14
|
+
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
|
15
|
+
<link rel="stylesheet" href="/music/music.css">
|
16
|
+
</head>
|
17
|
+
<body ng-controller="MainCtrl">
|
18
|
+
<div class="container">
|
19
|
+
<div class="row" ng-hide="!loggedIn">
|
20
|
+
<div class="col-md-12 well" style="display: flex; align-items: center;">
|
21
|
+
<div class="col-xs-4 col-md-2 col-md-offset-6">
|
22
|
+
<div class="form-group has-warning">
|
23
|
+
<input type="text" class="form-control" ng-model="search" placeholder="search"/>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<div class="col-xs-2 col-sm-1 col-sm-offset-6 col-md-offset-2 col-xs-offset-4">
|
27
|
+
<a ng-click="playRandom()" class="btn btn-danger btn-fab btn-raised fa fa-random"></a>
|
28
|
+
</div>
|
29
|
+
<div class="col-xs-2 col-sm-1">
|
30
|
+
<a ng-click="refresh()" class="btn btn-danger btn-fab btn-raised fa" ng-class="{ 'fa-sign-in': !loggedIn, 'fa-sign-out': loggedIn}"></a>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
<div class="row" ng-show="!loggedIn">
|
35
|
+
<div class="well col-xs-8 col-xs-offset-2 col-sm-6 col-sm-offset-3 col-md-4 col-md-offset-4">
|
36
|
+
<form class="form-horizontal">
|
37
|
+
<fieldset>
|
38
|
+
<!-- <legend>Sign in</legend> -->
|
39
|
+
<div class="form-group has-warning">
|
40
|
+
<!-- <label for="inputApiKey" class="col-lg-2 control-label">api_key</label> -->
|
41
|
+
<div class="col-lg-12">
|
42
|
+
<input type="text" class="form-control input-lg" ng-model="json.api_key" id="inputApiKey" placeholder="api_key">
|
43
|
+
</div>
|
44
|
+
<!-- <label for="inputSecret" class="col-lg-2 control-label">secret</label> -->
|
45
|
+
<div class="col-lg-12">
|
46
|
+
<input type="password" class="form-control input-lg" ng-model="json.secret" id="inputSecret" placeholder="secret">
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
<div class="form-group">
|
50
|
+
<div class="col-lg-10 col-lg-offset-2 text-center">
|
51
|
+
<button type="submit" class="btn btn-danger" ng-click="refresh()">login</button>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
</fieldset>
|
55
|
+
</form>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<div class="row" ng-show="loggedIn">
|
60
|
+
<div class="col-md-6">
|
61
|
+
<div class="embed-responsive embed-responsive-16by9 well">
|
62
|
+
<youtube-video class="embed-responsive-item" video-url="ytVideoUrl" player="bestPlayer" player-vars="playerVars"></youtube-video>
|
63
|
+
</div>
|
64
|
+
</div>
|
65
|
+
<div class="col-md-6">
|
66
|
+
<div class="list-group well">
|
67
|
+
<div ng-repeat="result in results | filter: search">
|
68
|
+
<div class="list-group-item vertical-center" ng-class="{ selected: isSelected(result) }">
|
69
|
+
<div class="row-action-primary">
|
70
|
+
<i class="fa fa-edit" ng-click="select(result)" data-toggle="modal" data-target="#complete-dialog"></i>
|
71
|
+
</div>
|
72
|
+
<div class="row-content" style="display: flex; align-items: center;">
|
73
|
+
<div class="least-content row-action-primary">
|
74
|
+
</div>
|
75
|
+
<div ng-click="play(result)">
|
76
|
+
<h4 class="list-group-item-heading no-wrap">{{ result.name || result}}</h4>
|
77
|
+
<p class="disabled list-group-item-text no-wrap disabled">{{ result.url }}</p>
|
78
|
+
</div>
|
79
|
+
</div>
|
80
|
+
</div>
|
81
|
+
<div class="list-group-separator"></div>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
<div ng-show="loggedIn">
|
87
|
+
<a ng-click="newSong()" data-toggle="modal" data-target="#complete-dialog" class="btn btn-danger btn-fab btn-raised fa fa-plus add-button"></a>
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<div id="complete-dialog" class="modal fade" tabindex="-1">
|
91
|
+
<div class="modal-dialog modal-sm">
|
92
|
+
<div class="modal-content">
|
93
|
+
<div class="modal-header">
|
94
|
+
<!-- <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> -->
|
95
|
+
<div class="form-group has-warning">
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
<div class="modal-body">
|
99
|
+
<div class="form-group has-warning">
|
100
|
+
<input class="form-control" ng-model="selected.name" placeholder="title" />
|
101
|
+
<input class="form-control" ng-model="selected.url" placeholder="url" />
|
102
|
+
<input class="form-control" ng-model="selected.moods" placeholder="moods" ng-list required>
|
103
|
+
</div>
|
104
|
+
</div>
|
105
|
+
<div class="modal-footer">
|
106
|
+
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
107
|
+
<button type="button" class="btn btn-danger" ng-click="save(selected)">Save changes</button>
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
|
113
|
+
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
|
114
|
+
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
|
115
|
+
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
|
116
|
+
|
117
|
+
<script src="/bootstrap-material-design/dist/js/ripples.min.js"></script>
|
118
|
+
<script src="/bootstrap-material-design/dist/js/material.min.js"></script>
|
119
|
+
|
120
|
+
<script src="//www.youtube.com/iframe_api"></script>
|
121
|
+
<script src="/music/angular-youtube-embed.js"></script>
|
122
|
+
|
123
|
+
<script src="/javascripts/jnorthpole.js"></script>
|
124
|
+
<script src="/music/music.js"></script>
|
125
|
+
</body>
|
126
|
+
</html>
|
@@ -0,0 +1,99 @@
|
|
1
|
+
$(() ->
|
2
|
+
$.material.init()
|
3
|
+
)
|
4
|
+
|
5
|
+
app = angular.module('app', [ 'youtube-embed' ])
|
6
|
+
|
7
|
+
app.controller 'MainCtrl', ($scope, youtubeEmbedUtils) ->
|
8
|
+
|
9
|
+
$scope.refresh = ->
|
10
|
+
if $scope.loggedIn
|
11
|
+
$scope.loggedIn = false
|
12
|
+
$scope.results = []
|
13
|
+
localStorage.clear()
|
14
|
+
$scope.json =
|
15
|
+
'api_key': 'guest'
|
16
|
+
'secret': 'guest'
|
17
|
+
'category': 'music'
|
18
|
+
else
|
19
|
+
$scope.loggedIn = false
|
20
|
+
jNorthPole.getStorage $scope.json, (data) ->
|
21
|
+
if $scope.json.apiKey != 'guest' and !data.error?
|
22
|
+
localStorage.json = angular.toJson($scope.json)
|
23
|
+
unless data.error? and data.api_key != 'guest'
|
24
|
+
$scope.apiKey = $scope.json.apiKey
|
25
|
+
$scope.results = data
|
26
|
+
$scope.loggedIn = true
|
27
|
+
$scope.$apply()
|
28
|
+
return
|
29
|
+
|
30
|
+
return
|
31
|
+
|
32
|
+
jNorthPole.BASE_URL = 'https://json.northpole.ro/'
|
33
|
+
$scope.results = []
|
34
|
+
$scope.playerVars =
|
35
|
+
controls: 1
|
36
|
+
autoplay: 1
|
37
|
+
if localStorage.json == undefined
|
38
|
+
$scope.json =
|
39
|
+
'api_key': 'guest'
|
40
|
+
'secret': 'guest'
|
41
|
+
'category': 'music'
|
42
|
+
else
|
43
|
+
$scope.json = angular.fromJson(localStorage.json)
|
44
|
+
$scope.refresh()
|
45
|
+
|
46
|
+
$scope.play = (video) ->
|
47
|
+
return unless video?
|
48
|
+
if $scope.ytVideoUrl == video.url and $scope.bestPlayer? and $scope.bestPlayer.getPlayerState() == 1
|
49
|
+
$scope.bestPlayer.pauseVideo()
|
50
|
+
else
|
51
|
+
$scope.ytVideoUrl = video.url
|
52
|
+
$scope.bestPlayer.playVideo() if $scope.bestPlayer?
|
53
|
+
# console.log youtubeEmbedUtils.getIdFromURL($scope.ytVideoUrl)
|
54
|
+
return
|
55
|
+
|
56
|
+
$scope.edit = (video) ->
|
57
|
+
$scope.selected = video
|
58
|
+
return
|
59
|
+
|
60
|
+
$scope.save = (video) ->
|
61
|
+
$scope.selected.secret = $scope.json.secret
|
62
|
+
json = angular.copy($scope.selected)
|
63
|
+
|
64
|
+
log = (data) ->
|
65
|
+
console.log data
|
66
|
+
return
|
67
|
+
|
68
|
+
if video.id?
|
69
|
+
jNorthPole.putStorage json, log
|
70
|
+
else
|
71
|
+
json.api_key = $scope.json.api_key
|
72
|
+
json.category = 'music'
|
73
|
+
jNorthPole.createStorage json, log
|
74
|
+
$('#complete-dialog').modal('hide')
|
75
|
+
$scope.selected = undefined
|
76
|
+
return
|
77
|
+
|
78
|
+
$scope.newSong = ->
|
79
|
+
$scope.selected = {}
|
80
|
+
return
|
81
|
+
|
82
|
+
$scope.select = (json) ->
|
83
|
+
$scope.selected = json
|
84
|
+
return
|
85
|
+
|
86
|
+
$scope.isSelected = (video) ->
|
87
|
+
$scope.ytVideoUrl == video.url
|
88
|
+
|
89
|
+
$scope.playRandom = ->
|
90
|
+
item = $scope.results[Math.floor(Math.random() * $scope.results.length)]
|
91
|
+
$scope.play item
|
92
|
+
if player?
|
93
|
+
player.seekTo 0
|
94
|
+
return
|
95
|
+
|
96
|
+
$scope.$on 'youtube.player.ended', ($event, player) ->
|
97
|
+
$scope.playRandom player
|
98
|
+
return
|
99
|
+
return
|
@@ -0,0 +1,63 @@
|
|
1
|
+
$size: 56px
|
2
|
+
|
3
|
+
html, body
|
4
|
+
height: 100%
|
5
|
+
|
6
|
+
.bear
|
7
|
+
background: url(/images/bear.png) no-repeat center center
|
8
|
+
|
9
|
+
.embed-responsive
|
10
|
+
position: relative
|
11
|
+
display: block
|
12
|
+
height: 0
|
13
|
+
padding: 0
|
14
|
+
overflow: hidden
|
15
|
+
|
16
|
+
.embed-responsive.embed-responsive-16by9
|
17
|
+
padding-bottom: 56.25%
|
18
|
+
|
19
|
+
.embed-responsive-item
|
20
|
+
@extend .bear
|
21
|
+
position: absolute
|
22
|
+
top: 0
|
23
|
+
bottom: 0
|
24
|
+
left: 0
|
25
|
+
width: 100%
|
26
|
+
height: 100%
|
27
|
+
border: 0
|
28
|
+
|
29
|
+
.container
|
30
|
+
z-index: 10
|
31
|
+
|
32
|
+
.content-container
|
33
|
+
padding-top: $size + 10px
|
34
|
+
padding-bottom: $size - 10px
|
35
|
+
|
36
|
+
.add-button
|
37
|
+
margin-bottom: 10px !important
|
38
|
+
margin-right: 10px !important
|
39
|
+
position: fixed
|
40
|
+
right: 0
|
41
|
+
bottom: 0
|
42
|
+
|
43
|
+
.no-wrap
|
44
|
+
white-space: nowrap
|
45
|
+
overflow: hidden
|
46
|
+
text-overflow: ellipsis
|
47
|
+
|
48
|
+
.vertical-center
|
49
|
+
display: flex
|
50
|
+
align-items: center
|
51
|
+
|
52
|
+
p.disabled
|
53
|
+
color: #bdbdbd
|
54
|
+
|
55
|
+
.selected
|
56
|
+
background-color: red !important
|
57
|
+
p
|
58
|
+
color: #f5f5f5
|
59
|
+
h4
|
60
|
+
color: #f5f5f5 !important
|
61
|
+
|
62
|
+
.list-group-separator
|
63
|
+
background-color: white
|
@@ -8,6 +8,8 @@
|
|
8
8
|
%br
|
9
9
|
%a{href: '#register'} How do I register?
|
10
10
|
%br
|
11
|
+
%a{href: '#realtime'} Is there an experimental realtime module?
|
12
|
+
%br
|
11
13
|
%h3#what What is json.northpole.ro?
|
12
14
|
%p
|
13
15
|
json.northpole.ro is a JSON cloud storage service.
|
@@ -36,3 +38,8 @@
|
|
36
38
|
%a{href: '/playground'} playground
|
37
39
|
\. If you can't do that, there is a good chance you don't understand
|
38
40
|
how the API works. Think of it as a tutorial.
|
41
|
+
%h3#realtime Is there an experimental realtime module?
|
42
|
+
%p
|
43
|
+
Yes. Go to
|
44
|
+
%a{href: '/websocket'} /websocket
|
45
|
+
to give it a spin.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ki::ChannelManager do
|
4
|
+
let(:cm) { Ki::ChannelManager }
|
5
|
+
let(:db) { Ki::Orm::Db.instance }
|
6
|
+
|
7
|
+
it 'returns the db connection' do
|
8
|
+
expect(cm.db).to eq db
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'stores a socket on connection' do
|
12
|
+
expect {
|
13
|
+
cm.connect
|
14
|
+
}.to change { db.count 'realtime_channel_sockets' }.by(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'removes a channel socket on disconnect' do
|
18
|
+
socket = cm.connect
|
19
|
+
expect {
|
20
|
+
cm.disconnect(socket)
|
21
|
+
}.to change { db.count 'realtime_channel_sockets' }.by(-1)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'removes all the channel subscriptions on disconnect' do
|
25
|
+
socket = cm.connect
|
26
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel')
|
27
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel-2')
|
28
|
+
expect {
|
29
|
+
cm.disconnect(socket)
|
30
|
+
}.to change { db.count 'realtime_channel_subscriptions' }.by(-2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns the list of channel sockets' do
|
34
|
+
cm.cleanup
|
35
|
+
expect(cm.sockets).to be_empty
|
36
|
+
|
37
|
+
cm.connect
|
38
|
+
expect(cm.sockets).to_not be_empty
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'subscribes to a channel' do
|
42
|
+
socket = cm.connect
|
43
|
+
|
44
|
+
expect {
|
45
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel')
|
46
|
+
}.to change { db.count 'realtime_channel_subscriptions' }.by(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not subscribe to the same channel twice' do
|
50
|
+
socket = cm.connect
|
51
|
+
|
52
|
+
expect {
|
53
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel')
|
54
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel')
|
55
|
+
}.to change { db.count 'realtime_channel_subscriptions' }.by(1)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'unsubscribes fom a channel' do
|
59
|
+
socket = cm.connect
|
60
|
+
cm.subscribe(socket_id: socket['id'], type: 'subscribe', 'channel_name' => 'test-channel')
|
61
|
+
|
62
|
+
expect {
|
63
|
+
cm.unsubscribe(socket_id: socket['id'], 'type' => 'unsubscribe', 'channel_name' => 'test-channel')
|
64
|
+
}.to change { db.count 'realtime_channel_subscriptions' }.by(-1)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns messages from a tick'
|
68
|
+
|
69
|
+
it 'publishes a message' do
|
70
|
+
expect {
|
71
|
+
item = cm.publish(hello: 'world')
|
72
|
+
expect(item['created_at']).to_not be_nil # TODO: might need present?
|
73
|
+
}.to change { db.count 'realtime_channel_messages' }.by(1)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'cleans up the data' do
|
77
|
+
cm.cleanup
|
78
|
+
expect(db.count('realtime_channel_sockets')).to eq 0
|
79
|
+
expect(db.count('realtime_channel_subscriptions')).to eq 0
|
80
|
+
expect(db.count('realtime_channel_messages')).to eq 0
|
81
|
+
end
|
82
|
+
end
|