first commit
This commit is contained in:
commit
b2502bd29e
19 files changed
+556
No files matched your search
+24
@@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 didier amyot
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/influxdb/influxdb/client"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
var hashKey = []byte("0ea20ffa64fb127136be5bb9fb0814289267f6d162c81f06af237a09e375d182bada41b9ba14eb4d34f73c9c8b792fc0")
|
||||
var s = securecookie.New(hashKey, nil)
|
||||
|
||||
type Data struct {
|
||||
IncluxDB *client.Client
|
||||
}
|
||||
|
||||
func (d *Data) CreateUserId(w http.ResponseWriter) bson.ObjectId {
|
||||
id := bson.NewObjectId()
|
||||
|
||||
if encoded, err := s.Encode("onepixel", map[string]string{"id": id.Hex()}); err == nil {
|
||||
cookie := &http.Cookie{
|
||||
Name: "onepixel",
|
||||
Value: encoded,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
} else {
|
||||
log.Println("cannot encrypt uuid")
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func (d *Data) GetUserIdInCookie(r *http.Request) bson.ObjectId {
|
||||
if cookie, err := r.Cookie("onepixel"); err == nil {
|
||||
value := make(map[string]string)
|
||||
if err = s.Decode("onepixel", cookie.Value, &value); err == nil {
|
||||
if bson.IsObjectIdHex(value["id"]) {
|
||||
return bson.ObjectIdHex(value["id"])
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d *Data) GetAndSetId(w http.ResponseWriter, request *http.Request) bson.ObjectId {
|
||||
if id := d.GetUserIdInCookie(request); id.Valid() {
|
||||
return id
|
||||
} else {
|
||||
return d.CreateUserId(w)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Data) ServeHTTP(w http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
|
||||
ip, _, _ := net.SplitHostPort(request.RemoteAddr)
|
||||
|
||||
userAgent := request.UserAgent()
|
||||
useId := d.GetAndSetId(w, request)
|
||||
url := vars["url"]
|
||||
serieName := vars["serie_name"]
|
||||
|
||||
d.AddDataPoint(serieName, url, userAgent, ip, useId)
|
||||
}
|
||||
|
||||
func (d *Data) CreateSeries(serieName, url, userAgent, ip string, userId bson.ObjectId) []*client.Series {
|
||||
series := &client.Series{
|
||||
Name: serieName,
|
||||
Columns: []string{"url", "user_id", "user_agent", "ip"},
|
||||
Points: [][]interface{}{
|
||||
{url, userId, userAgent, ip},
|
||||
},
|
||||
}
|
||||
return []*client.Series{series}
|
||||
}
|
||||
|
||||
func (d *Data) AddDataPoint(serieName, url, userAgent, ip string, userId bson.ObjectId) {
|
||||
fmt.Println("serieName :", serieName)
|
||||
fmt.Println("url :", url)
|
||||
fmt.Println("id :", userId.Hex())
|
||||
fmt.Println("userAgent :", userAgent)
|
||||
fmt.Println("")
|
||||
|
||||
series := d.CreateSeries(serieName, url, userAgent, ip, userId)
|
||||
if err := d.IncluxDB.WriteSeries(series); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MockResponseWriter struct {
|
||||
header http.Header
|
||||
}
|
||||
|
||||
func NewMockResponseWriter() http.ResponseWriter {
|
||||
var header http.Header = make(map[string][]string)
|
||||
return &MockResponseWriter{header}
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) Header() http.Header {
|
||||
return m.header
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) Write(b []byte) (int, error) {
|
||||
return 500, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (m *MockResponseWriter) WriteHeader(c int) {}
|
||||
|
||||
func TestSecureCookie(t *testing.T) {
|
||||
w := NewMockResponseWriter()
|
||||
d := new(Data)
|
||||
|
||||
uuid := d.CreateUserId(w)
|
||||
|
||||
if !uuid.Valid() {
|
||||
t.Error("invalid uuid")
|
||||
}
|
||||
|
||||
if w.Header().Get("Set-Cookie") == "" {
|
||||
t.Error("nothing in set in the cookie")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package data
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/didiercrunch/onepixel/data"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const STATIC_DIR_PATH = "static/"
|
||||
|
||||
func serveStatic(router *mux.Router) {
|
||||
handler := func(w http.ResponseWriter, request *http.Request) {
|
||||
vars := mux.Vars(request)
|
||||
filepath := "/" + vars["path"]
|
||||
w.Header().Set("Cache-Control", "public, max-age=43200")
|
||||
http.ServeFile(w, request, path.Join(STATIC_DIR_PATH, filepath))
|
||||
}
|
||||
router.HandleFunc("/{path:.*}", handler)
|
||||
}
|
||||
|
||||
func serveApi(router *mux.Router, apiHandler http.Handler) {
|
||||
router.Handle("/api/{serie_name}/{url:.*}", apiHandler)
|
||||
}
|
||||
|
||||
func createMuxRouter() http.Handler {
|
||||
r := mux.NewRouter()
|
||||
serveApi(r, &data.Data{params.InfluxDBClient})
|
||||
serveStatic(r.PathPrefix("/").Subrouter())
|
||||
return r
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := createMuxRouter()
|
||||
http.Handle("/", r)
|
||||
address := params.Host + ":" + strconv.Itoa(params.Port)
|
||||
if err := http.ListenAndServe(address, createMuxRouter()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
package main
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"github.com/influxdb/influxdb/client"
|
||||
|
||||
goyaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const PARAM_FILE string = "params.yml"
|
||||
|
||||
type Params struct {
|
||||
Port int `yaml:"port,omitempty"`
|
||||
Host string `yaml:"host,omitempty"`
|
||||
InfluxDBClientConfig *client.ClientConfig `yaml:"influxdb,omitempty"`
|
||||
InfluxDBClient *client.Client `yaml:"-"`
|
||||
}
|
||||
|
||||
func (this *Params) LoadFromYamlFile(fileName string) error {
|
||||
data, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return this.LoadFromYamlData(data)
|
||||
}
|
||||
|
||||
func (this *Params) LoadFromYamlData(data []byte) error {
|
||||
var err error
|
||||
p := new(Params)
|
||||
if err = goyaml.Unmarshal(data, p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Host != "" {
|
||||
this.Host = p.Host
|
||||
}
|
||||
if p.Port > 0 {
|
||||
this.Port = p.Port
|
||||
}
|
||||
if p.InfluxDBClientConfig == nil {
|
||||
return nil
|
||||
}
|
||||
if p.InfluxDBClientConfig.Host != "" {
|
||||
this.InfluxDBClientConfig.Host = p.InfluxDBClientConfig.Host
|
||||
}
|
||||
if p.InfluxDBClientConfig.Database != "" {
|
||||
this.InfluxDBClientConfig.Database = p.InfluxDBClientConfig.Database
|
||||
}
|
||||
if p.InfluxDBClientConfig.Password != "" {
|
||||
this.InfluxDBClientConfig.Password = p.InfluxDBClientConfig.Password
|
||||
}
|
||||
if p.InfluxDBClientConfig.Username != "" {
|
||||
this.InfluxDBClientConfig.Username = p.InfluxDBClientConfig.Username
|
||||
}
|
||||
this.InfluxDBClientConfig.IsSecure = p.InfluxDBClientConfig.IsSecure
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Params) initInfluxDB() error {
|
||||
var err error
|
||||
this.InfluxDBClient, err = client.NewClient(this.InfluxDBClientConfig)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDefaultParams() *Params {
|
||||
influxdbClientConfig := &client.ClientConfig{}
|
||||
return &Params{7777, "localhost", influxdbClientConfig, nil}
|
||||
}
|
||||
|
||||
var params = GetDefaultParams()
|
||||
|
||||
func init() {
|
||||
if err := params.LoadFromYamlFile(PARAM_FILE); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := params.initInfluxDB(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
|
||||
|
||||
# This is onepixel params' file. The file is in yaml format. The file
|
||||
# should be auto-documented
|
||||
|
||||
|
||||
# the port where the onepixel web site will run
|
||||
port: 6900
|
||||
|
||||
# the host name. 0.0.0.0 to share the service with everyone on the network.
|
||||
# localhost for running on localhost without the possibility to share the
|
||||
# service
|
||||
host: 0.0.0.0 #localhost
|
||||
|
||||
|
||||
|
||||
# all the params relative to inflixdb
|
||||
influxdb:
|
||||
host: ~
|
||||
username: root
|
||||
password: root
|
||||
database: onepixel
|
||||
issecure: yes
|
||||
@@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const yaml_params = `
|
||||
---
|
||||
|
||||
port: 9999
|
||||
|
||||
host: 0.0.0.0 #localhost
|
||||
|
||||
# all the params relative to mongodb
|
||||
influxdb:
|
||||
host: "bigtits.com"
|
||||
username: "alice"
|
||||
password: "qwerty"
|
||||
database: "tits"
|
||||
issecure: yes
|
||||
`
|
||||
|
||||
func TestLoadFromYamlData(t *testing.T) {
|
||||
p := GetDefaultParams()
|
||||
if err := p.LoadFromYamlData([]byte(yaml_params)); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if p.Port != 9999 {
|
||||
t.Error("port")
|
||||
}
|
||||
if p.Host != "0.0.0.0" {
|
||||
t.Error("host")
|
||||
}
|
||||
if p.InfluxDBClientConfig.Host != "bigtits.com" {
|
||||
t.Error("InfluxDBClientConfig.Host", p.InfluxDBClientConfig.Host, " fuck")
|
||||
}
|
||||
if p.InfluxDBClientConfig.Database != "tits" {
|
||||
t.Error("InfluxDBClientConfig.Database")
|
||||
}
|
||||
if !p.InfluxDBClientConfig.IsSecure {
|
||||
t.Error("InfluxDBClientConfig.IsSecure")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
define [
|
||||
"angular"
|
||||
"filters"
|
||||
"services"
|
||||
"directives"
|
||||
"controllers"
|
||||
"angularRoute"
|
||||
], (angular, filters, services, directives, controllers) ->
|
||||
|
||||
# Declare app level module which depends on filters, and services
|
||||
angular.module "myApp", [
|
||||
"ngRoute"
|
||||
"myApp.filters"
|
||||
"myApp.services"
|
||||
"myApp.directives"
|
||||
"myApp.controllers"
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
define [], ->
|
||||
[
|
||||
"$scope"
|
||||
"$http"
|
||||
($scope, $http) ->
|
||||
|
||||
# You can access the scope of the controller from here
|
||||
$scope.welcomeMessage = "hey this is myctrl2.js!"
|
||||
|
||||
# because this has happened asynchroneusly we've missed
|
||||
# Angular's initial call to $apply after the controller has been loaded
|
||||
# hence we need to explicityly call it at the end of our Controller constructor
|
||||
$scope.$apply()
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
define [
|
||||
"angular"
|
||||
"services"
|
||||
], (angular, services) ->
|
||||
|
||||
# Directives
|
||||
angular.module("myApp.directives", ["myApp.services"]).directive "appVersion", [
|
||||
"version"
|
||||
(version) ->
|
||||
return (scope, elm, attrs) ->
|
||||
elm.text version
|
||||
return
|
||||
]
|
||||
return
|
||||
@@ -0,0 +1,32 @@
|
||||
require.config
|
||||
paths:
|
||||
angular: "../bower_components/angular/angular"
|
||||
angularRoute: "../bower_components/angular-route/angular-route"
|
||||
angularMocks: "../bower_components/angular-mocks/angular-mocks"
|
||||
text: "../bower_components/requirejs-text/text"
|
||||
|
||||
shim:
|
||||
angular:
|
||||
exports: "angular"
|
||||
|
||||
angularRoute: ["angular"]
|
||||
angularMocks:
|
||||
deps: ["angular"]
|
||||
exports: "angular.mock"
|
||||
|
||||
priority: ["angular"]
|
||||
|
||||
|
||||
#http://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap
|
||||
window.name = "NG_DEFER_BOOTSTRAP!"
|
||||
require [
|
||||
"angular"
|
||||
"app"
|
||||
"routes"
|
||||
], (angular, app, routes) ->
|
||||
$html = angular.element(document.getElementsByTagName("html")[0])
|
||||
angular.element().ready ->
|
||||
angular.resumeBootstrap [app["name"]]
|
||||
return
|
||||
|
||||
return
|
||||
@@ -0,0 +1,17 @@
|
||||
define [
|
||||
"angular"
|
||||
"app"
|
||||
], (angular, app) ->
|
||||
app.config [
|
||||
"$routeProvider"
|
||||
($routeProvider) ->
|
||||
$routeProvider.when "/view1",
|
||||
templateUrl: "app/partials/partial1.html"
|
||||
controller: "MyCtrl1"
|
||||
|
||||
$routeProvider.when "/view2",
|
||||
templateUrl: "app/partials/partial2.html"
|
||||
controller: "MyCtrl2"
|
||||
|
||||
$routeProvider.otherwise redirectTo: "/view1"
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
define ["angular"], (angular) ->
|
||||
|
||||
# Services
|
||||
|
||||
# Demonstrate how to register services
|
||||
# In this case it is a simple value service.
|
||||
angular.module("myApp.services", []).value "version", "0.1"
|
||||
return
|
||||
@@ -0,0 +1,34 @@
|
||||
var bower = require('gulp-bower');
|
||||
var gulp = require('gulp');
|
||||
var coffee = require('gulp-coffee');
|
||||
var help = require('gulp-task-listing');
|
||||
var clean = require('gulp-clean');
|
||||
|
||||
|
||||
|
||||
gulp.task('help', help);
|
||||
|
||||
gulp.task('bower', function() {
|
||||
return bower()
|
||||
.pipe(gulp.dest('bower_components/'))
|
||||
});
|
||||
|
||||
gulp.task('coffee', function() {
|
||||
gulp.src('app/coffee/**/*.coffee')
|
||||
.pipe(coffee({bare: true}))
|
||||
.pipe(gulp.dest('./app/js/'))
|
||||
});
|
||||
|
||||
gulp.task('clean', function(){
|
||||
return gulp.src(["js/", "bower_components/"], {read: false})
|
||||
.pipe(clean())
|
||||
});
|
||||
|
||||
|
||||
gulp.task('default', ['bower', 'coffee']);
|
||||
|
||||
|
||||
|
||||
gulp.task('dev', ['bower', 'coffee'], function(){
|
||||
gulp.watch('coffee/**/*.coffee', ['coffee']);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lt IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html lang="en" ng-app="myApp" class="no-js"> <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Angular-RequireJS sample app</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="app/bower_components/html5-boilerplate/css/normalize.css">
|
||||
<link rel="stylesheet" href="app/bower_components/html5-boilerplate/css/main.css">
|
||||
<link rel="stylesheet" href="app/css/app.css"/>
|
||||
<script src="app/bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AngularJS + RequireJS</h1>
|
||||
<ul class="menu">
|
||||
<li><a href="#/view1">view1</a></li>
|
||||
<li><a href="#/view2">view2</a></li>
|
||||
</ul>
|
||||
|
||||
<!--[if lt IE 7]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
|
||||
<div ng-view></div>
|
||||
|
||||
<div>AngularJS + RequireJS seed app: v<span app-version></span></div>
|
||||
<script data-main="app/js/main" src="app/bower_components/requirejs/require.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"gulp-task-listing": "~0.3.0",
|
||||
"gulp-clean": "~0.3.1",
|
||||
"gulp-coffee": "~2.2.0",
|
||||
"gulp": "~3.8.9",
|
||||
"gulp-bower": "0.0.7"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user