mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-24 08:02:18 +02:00
got websockets working. added stubs for html5 notifications api
This commit is contained in:
parent
77daa5743f
commit
e8abb11c19
@ -6,6 +6,8 @@ env:
|
|||||||
- PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
- PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
||||||
script:
|
script:
|
||||||
- sudo apt-get -y install libsqlite3-dev sqlite3 1> /dev/null 2> /dev/null
|
- sudo apt-get -y install libsqlite3-dev sqlite3 1> /dev/null 2> /dev/null
|
||||||
|
- sudo npm install -g uglify-js
|
||||||
|
- sudo npm install -g less
|
||||||
- make deps
|
- make deps
|
||||||
- make build
|
- make build
|
||||||
- make test
|
- make test
|
||||||
|
@ -37,7 +37,9 @@
|
|||||||
<script src="/scripts/services/conf.js"></script>
|
<script src="/scripts/services/conf.js"></script>
|
||||||
<script src="/scripts/services/repo.js"></script>
|
<script src="/scripts/services/repo.js"></script>
|
||||||
<script src="/scripts/services/user.js"></script>
|
<script src="/scripts/services/user.js"></script>
|
||||||
<script src="/scripts/services/ws.js"></script>
|
<script src="/scripts/services/feed.js"></script>
|
||||||
|
<script src="/scripts/services/notify.js"></script>
|
||||||
|
<script src="/scripts/services/stdout.js"></script>
|
||||||
<script src="/scripts/filters/filters.js"></script>
|
<script src="/scripts/filters/filters.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -280,14 +280,6 @@ app.controller("RepoController", function($scope, $http, $routeParams, user, rep
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.options={
|
|
||||||
barColor:"#40C598",
|
|
||||||
trackColor:'#EEEEEE',
|
|
||||||
scaleColor:false,
|
|
||||||
lineWidth:10,
|
|
||||||
lineCap:'butt',
|
|
||||||
size:130
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller("BranchController", function($scope, $http, $routeParams, user) {
|
app.controller("BranchController", function($scope, $http, $routeParams, user) {
|
||||||
@ -327,15 +319,21 @@ app.controller("BranchController", function($scope, $http, $routeParams, user) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller("CommitController", function($scope, $http, $routeParams, user) {
|
app.controller("CommitController", function($scope, $http, $routeParams, stdout, feed) {
|
||||||
|
|
||||||
$scope.user = user;
|
|
||||||
var remote = $routeParams.remote;
|
var remote = $routeParams.remote;
|
||||||
var owner = $routeParams.owner;
|
var owner = $routeParams.owner;
|
||||||
var name = $routeParams.name;
|
var name = $routeParams.name;
|
||||||
var branch = $routeParams.branch;
|
var branch = $routeParams.branch;
|
||||||
var commit = $routeParams.commit;
|
var commit = $routeParams.commit;
|
||||||
|
|
||||||
|
feed.subscribe(function(event) {
|
||||||
|
if (event.commit.sha == commit
|
||||||
|
&& event.commit.branch == branch) {
|
||||||
|
$scope.commit = event.commit;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// load the repo meta-data
|
// load the repo meta-data
|
||||||
$http({method: 'GET', url: '/v1/repos/'+remote+'/'+owner+"/"+name}).
|
$http({method: 'GET', url: '/v1/repos/'+remote+'/'+owner+"/"+name}).
|
||||||
success(function(data, status, headers, config) {
|
success(function(data, status, headers, config) {
|
||||||
@ -351,6 +349,14 @@ app.controller("CommitController", function($scope, $http, $routeParams, user) {
|
|||||||
$scope.commit = data;
|
$scope.commit = data;
|
||||||
$scope.coverage=45;
|
$scope.coverage=45;
|
||||||
$scope.passing=100;
|
$scope.passing=100;
|
||||||
|
|
||||||
|
if (data.status!='Started' && data.status!='Pending') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout.subscribe(data.id, function(out){
|
||||||
|
console.log(out);
|
||||||
|
});
|
||||||
}).
|
}).
|
||||||
error(function(data, status, headers, config) {
|
error(function(data, status, headers, config) {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -375,21 +381,6 @@ app.controller("CommitController", function($scope, $http, $routeParams, user) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$scope.options={
|
|
||||||
barColor:"#40C598",
|
|
||||||
trackColor:'#EEEEEE',
|
|
||||||
scaleColor:false,
|
|
||||||
lineWidth:10,
|
|
||||||
lineCap:'butt',
|
|
||||||
size:130
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function barColor(percent) {
|
|
||||||
switch(true) {
|
|
||||||
case percent > 80: return "#40C598";
|
|
||||||
case percent < 50: return "rgba(189, 54, 47, 0.8)";
|
|
||||||
default: return "#f0ad4e";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('app').controller("HomeController", function($scope, $http, user, websocket) {
|
angular.module('app').controller("HomeController", function($scope, $http, feed, notify) {
|
||||||
|
|
||||||
$scope.user = user;
|
feed.subscribe(function(message) {
|
||||||
|
notify.send(message.repo.name);
|
||||||
websocket.subscribeRepos(function(repos) {
|
|
||||||
console.log(repos);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$http({method: 'GET', url: '/v1/user/feed'}).
|
$http({method: 'GET', url: '/v1/user/feed'}).
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('app').controller("UserController", function($scope, $http, user) {
|
angular.module('app').controller("UserController", function($scope, $http, user, notify) {
|
||||||
|
|
||||||
$scope.user = user;
|
$scope.user = user;
|
||||||
|
|
||||||
@ -17,6 +17,10 @@ angular.module('app').controller("UserController", function($scope, $http, user)
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.notifications = {}
|
||||||
|
$scope.notifications.supported = notify.supported();
|
||||||
|
$scope.notifications.granted = notify.granted();
|
||||||
|
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
// request to create a new repository
|
// request to create a new repository
|
||||||
$http({method: 'PUT', url: '/v1/user', data: $scope.userTemp }).
|
$http({method: 'PUT', url: '/v1/user', data: $scope.userTemp }).
|
||||||
@ -35,4 +39,7 @@ angular.module('app').controller("UserController", function($scope, $http, user)
|
|||||||
name : $scope.user.name
|
name : $scope.user.name
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
$scope.enableNotifications = function() {
|
||||||
|
notify.requestPermission();
|
||||||
|
};
|
||||||
});
|
});
|
24
server/app/scripts/services/feed.js
Normal file
24
server/app/scripts/services/feed.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('app').service('feed', ['$http', '$window', function($http, $window) {
|
||||||
|
|
||||||
|
var proto = ($window.location.protocol == 'https:' ? 'wss' : 'ws');
|
||||||
|
var route = [proto, "://", $window.location.host, '/ws/user'].join('');
|
||||||
|
|
||||||
|
var wsCallback = undefined;
|
||||||
|
var ws = new WebSocket(route);
|
||||||
|
ws.onmessage = function(event) {
|
||||||
|
var data = angular.fromJson(event.data);
|
||||||
|
if (wsCallback != undefined) {
|
||||||
|
wsCallback(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.subscribe = function(callback) {
|
||||||
|
wsCallback = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.unsubscribe = function() {
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
}]);
|
23
server/app/scripts/services/notify.js
Normal file
23
server/app/scripts/services/notify.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('app').service('notify', ['$window', '$timeout', function($window, $timeout) {
|
||||||
|
|
||||||
|
this.supported = function() {
|
||||||
|
return ("Notification" in $window)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.granted = function() {
|
||||||
|
return ("Notification" in $window) && Notification.permission === "granted";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.requestPermission = function() {
|
||||||
|
Notification.requestPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send = function(title, opts) {
|
||||||
|
if ("Notification" in $window) {
|
||||||
|
var n = new Notification(title, opts);
|
||||||
|
$timeout(function() { n.close(); }, 10000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
27
server/app/scripts/services/stdout.js
Normal file
27
server/app/scripts/services/stdout.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('app').service('stdout', ['$window', function($window) {
|
||||||
|
var callback = undefined;
|
||||||
|
var websocket = undefined;
|
||||||
|
|
||||||
|
this.subscribe = function(path, _callback) {
|
||||||
|
callback = _callback;
|
||||||
|
|
||||||
|
var proto = ($window.location.protocol == 'https:' ? 'wss' : 'ws');
|
||||||
|
var route = [proto, "://", $window.location.host, '/ws/stdout/', path].join('');
|
||||||
|
|
||||||
|
websocket = new WebSocket(route);
|
||||||
|
websocket.onmessage = function(event) {
|
||||||
|
if (callback != undefined) {
|
||||||
|
callback(event.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.unsubscribe = function() {
|
||||||
|
callback = undefined;
|
||||||
|
if (webscoket != undefined) {
|
||||||
|
websocket.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
angular.module('app').service('websocket', function($q, $http, $window) {
|
|
||||||
var wsCallback = undefined;
|
|
||||||
var ws = new WebSocket('ws://localhost:8080/ws/user');
|
|
||||||
ws.onmessage = function(event) {
|
|
||||||
var data = angular.fromJson(event.data);
|
|
||||||
if (wsCallback != undefined) {
|
|
||||||
wsCallback(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
subscribeRepos: function(callback) {
|
|
||||||
wsCallback = callback;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
@ -54,6 +54,10 @@
|
|||||||
{{failure}}
|
{{failure}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="notifications.supported && !notifications.granted">
|
||||||
|
<button ng-click="enableNotifications()">Enable Notifications</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button ng-click="save()">Save</button>
|
<button ng-click="save()">Save</button>
|
||||||
<button ng-click="cancel()">Cancel</button>
|
<button ng-click="cancel()">Cancel</button>
|
||||||
|
@ -27,6 +27,10 @@ type PermManager interface {
|
|||||||
// Admin returns true if the specified user is an
|
// Admin returns true if the specified user is an
|
||||||
// administrator of the repository.
|
// administrator of the repository.
|
||||||
Admin(u *model.User, r *model.Repo) (bool, error)
|
Admin(u *model.User, r *model.Repo) (bool, error)
|
||||||
|
|
||||||
|
// Member returns true if the specified user is a
|
||||||
|
// collaborator on the repository.
|
||||||
|
Member(u *model.User, r *model.Repo) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// permManager manages user permissions to access repositories.
|
// permManager manages user permissions to access repositories.
|
||||||
@ -147,6 +151,20 @@ func (db *permManager) Admin(u *model.User, r *model.Repo) (bool, error) {
|
|||||||
return perm.Admin, err
|
return perm.Admin, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *permManager) Member(u *model.User, r *model.Repo) (bool, error) {
|
||||||
|
switch {
|
||||||
|
// if the user is nil, deny access
|
||||||
|
case u == nil:
|
||||||
|
return false, nil
|
||||||
|
case u.ID == r.UserID:
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the permissions from the database
|
||||||
|
perm, err := db.find(u, r)
|
||||||
|
return perm.Read, err
|
||||||
|
}
|
||||||
|
|
||||||
func (db *permManager) find(u *model.User, r *model.Repo) (*perm, error) {
|
func (db *permManager) find(u *model.User, r *model.Repo) (*perm, error) {
|
||||||
var dst = perm{}
|
var dst = perm{}
|
||||||
var err = meddler.QueryRow(db, &dst, findPermQuery, u.ID, r.ID)
|
var err = meddler.QueryRow(db, &dst, findPermQuery, u.ID, r.ID)
|
||||||
|
@ -2,6 +2,7 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/server/database"
|
"github.com/drone/drone/server/database"
|
||||||
@ -77,7 +78,7 @@ func (h *WsHandler) WsUser(w http.ResponseWriter, r *http.Request) error {
|
|||||||
|
|
||||||
// user must have read access to the repository
|
// user must have read access to the repository
|
||||||
// in order to pass this message along
|
// in order to pass this message along
|
||||||
if ok, _ := h.perms.Read(user, work.Repo); !ok {
|
if ok, _ := h.perms.Member(user, work.Repo); !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,15 +110,13 @@ func (h *WsHandler) WsUser(w http.ResponseWriter, r *http.Request) error {
|
|||||||
// WsConsole will upgrade the connection to a Websocket and will stream
|
// WsConsole will upgrade the connection to a Websocket and will stream
|
||||||
// the build output to the browser.
|
// the build output to the browser.
|
||||||
func (h *WsHandler) WsConsole(w http.ResponseWriter, r *http.Request) error {
|
func (h *WsHandler) WsConsole(w http.ResponseWriter, r *http.Request) error {
|
||||||
var host, owner, name = parseRepo(r)
|
var commitID, _ = strconv.Atoi(r.FormValue(":id"))
|
||||||
var branch = r.FormValue(":branch")
|
|
||||||
var sha = r.FormValue(":commit")
|
|
||||||
|
|
||||||
repo, err := h.repos.FindName(host, owner, name)
|
commit, err := h.commits.Find(int64(commitID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return notFound{err}
|
return notFound{err}
|
||||||
}
|
}
|
||||||
commit, err := h.commits.FindSha(repo.ID, branch, sha)
|
repo, err := h.repos.Find(commit.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return notFound{err}
|
return notFound{err}
|
||||||
}
|
}
|
||||||
@ -212,5 +211,5 @@ func (h *WsHandler) Ping(w http.ResponseWriter, r *http.Request) error {
|
|||||||
func (h *WsHandler) Register(r *pat.Router) {
|
func (h *WsHandler) Register(r *pat.Router) {
|
||||||
r.Post("/ws/ping", errorHandler(h.Ping))
|
r.Post("/ws/ping", errorHandler(h.Ping))
|
||||||
r.Get("/ws/user", errorHandler(h.WsUser))
|
r.Get("/ws/user", errorHandler(h.WsUser))
|
||||||
r.Get("/ws/{host}/{owner}/{name}/branches/{branch}/commits/{commit}", errorHandler(h.WsConsole))
|
r.Get("/ws/stdout/{id}", errorHandler(h.WsConsole))
|
||||||
}
|
}
|
||||||
|
@ -19,3 +19,8 @@ var DefaultOpts = &Opts{
|
|||||||
Timeout: 0,
|
Timeout: 0,
|
||||||
Record: false,
|
Record: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ConsoleOpts = &Opts{
|
||||||
|
Timeout: time.Minute * 60,
|
||||||
|
Record: true,
|
||||||
|
}
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
User *model.User
|
User *model.User `json:"-"`
|
||||||
Repo *model.Repo
|
Repo *model.Repo `json:"repo"`
|
||||||
Commit *model.Commit
|
Commit *model.Commit `json:"commit"`
|
||||||
server *model.Server
|
server *model.Server
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,9 @@ func (w *worker) Execute(r *Request) {
|
|||||||
w.commits.Update(r.Commit)
|
w.commits.Update(r.Commit)
|
||||||
|
|
||||||
// notify all listeners that the build is started
|
// notify all listeners that the build is started
|
||||||
commitc := w.pubsub.Register("_")
|
commitc := w.pubsub.Register("_global")
|
||||||
commitc.Publish(r)
|
commitc.Publish(r)
|
||||||
stdoutc := w.pubsub.Register(r.Commit.ID)
|
stdoutc := w.pubsub.RegisterOpts(r.Commit.ID, pubsub.ConsoleOpts)
|
||||||
defer stdoutc.Close()
|
defer stdoutc.Close()
|
||||||
|
|
||||||
// create a special buffer that will also
|
// create a special buffer that will also
|
||||||
|
Loading…
Reference in New Issue
Block a user