1
0
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:
Brad Rydzewski 2014-06-22 02:04:07 -07:00
parent 77daa5743f
commit e8abb11c19
15 changed files with 145 additions and 63 deletions

View File

@ -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

View File

@ -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>

View File

@ -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";
}
}

View File

@ -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'}).

View File

@ -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();
};
}); });

View 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();
};
}]);

View 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);
}
};
}]);

View 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();
}
};
}]);

View File

@ -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;
}
};
});

View File

@ -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>

View File

@ -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)

View File

@ -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))
} }

View File

@ -19,3 +19,8 @@ var DefaultOpts = &Opts{
Timeout: 0, Timeout: 0,
Record: false, Record: false,
} }
var ConsoleOpts = &Opts{
Timeout: time.Minute * 60,
Record: true,
}

View File

@ -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
} }

View File

@ -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