ki 0.4.10 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|