diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afed073 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.csv diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..9e83a92 --- /dev/null +++ b/errors.go @@ -0,0 +1,9 @@ +package main + +import "fmt" + +func check(err error) { + if err != nil { + fmt.Println(err) + } +} diff --git a/ipFilter.go b/ipFilter.go new file mode 100644 index 0000000..67b513a --- /dev/null +++ b/ipFilter.go @@ -0,0 +1,30 @@ +package main + +import ( + "errors" + "fmt" + "net/http" + "strings" +) + +func ipFilter(w http.ResponseWriter, r *http.Request) { + var err error + fmt.Println(r.RemoteAddr) + reqIP := strings.Split(r.RemoteAddr, ":")[0] + for _, ip := range serverConfig.BlockedIPs { + if reqIP == ip { + err = errors.New("ip not allowed to post images") + } + } + + for _, ip := range serverConfig.AllowedIPs { + if reqIP != ip { + err = errors.New("ip not allowed to post images") + } + } + //return err + if err != nil { + fmt.Fprintln(w, err.Error()) + return + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..64b976f --- /dev/null +++ b/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" + + "github.com/fatih/color" + "github.com/gorilla/handlers" + mgo "gopkg.in/mgo.v2" +) + +var cellCollection *mgo.Collection + +func main() { + //connect with mongodb + readMongodbConfig("./mongodbConfig.json") + session, err := getSession() + check(err) + cellCollection = getCollection(session, "cells") + + if len(os.Args) > 1 { + if os.Args[1] == "-dataset" { + color.Blue("starting to read dataset") + readDataset("dataModel_head.csv") + color.Blue("finished reading dataset") + } + } + + //http server start + readServerConfig("./serverConfig.json") + color.Green("server running") + fmt.Print("port: ") + color.Green(serverConfig.ServerPort) + router := NewRouter() + + headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Access-Control-Allow-Origin"}) + originsOk := handlers.AllowedOrigins([]string{"*"}) + methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"}) + log.Fatal(http.ListenAndServe(":"+serverConfig.ServerPort, handlers.CORS(originsOk, headersOk, methodsOk)(router))) +} diff --git a/mongoModels.go b/mongoModels.go new file mode 100644 index 0000000..e0b9030 --- /dev/null +++ b/mongoModels.go @@ -0,0 +1,18 @@ +package main + +type CellModel struct { + Radio string `json:"radio"` + MCC string `json:"mcc"` + Net int `json:"net"` + Area int `json:"area"` + Cell int `json:"cell"` + Unit int `json:"unit"` + Lon float64 `json:"lon"` + Lat float64 `json:"lat"` + Range float64 `json:"range"` + Samples int `json:"samples"` + Changeable string `json:"changeable"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + AverageSignal float64 `json:"averagesignal"` +} diff --git a/mongoOperations.go b/mongoOperations.go new file mode 100644 index 0000000..696a6aa --- /dev/null +++ b/mongoOperations.go @@ -0,0 +1,47 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + + mgo "gopkg.in/mgo.v2" +) + +//MongoConfig stores the configuration of mongodb to connect +type MongoConfig struct { + Ip string `json:"ip"` + Database string `json:"database"` +} + +var mongoConfig MongoConfig + +func readMongodbConfig(path string) { + file, e := ioutil.ReadFile(path) + if e != nil { + fmt.Println("error:", e) + } + content := string(file) + json.Unmarshal([]byte(content), &mongoConfig) +} + +func getSession() (*mgo.Session, error) { + session, err := mgo.Dial("mongodb://" + mongoConfig.Ip) + if err != nil { + panic(err) + } + //defer session.Close() + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + return session, err +} +func getCollection(session *mgo.Session, collection string) *mgo.Collection { + + c := session.DB(mongoConfig.Database).C(collection) + return c +} diff --git a/mongodbConfig.json b/mongodbConfig.json new file mode 100644 index 0000000..d1859e9 --- /dev/null +++ b/mongodbConfig.json @@ -0,0 +1,4 @@ +{ + "ip": "127.0.0.1", + "database": "cellmap" +} diff --git a/readDataset.go b/readDataset.go new file mode 100644 index 0000000..f93d25c --- /dev/null +++ b/readDataset.go @@ -0,0 +1,42 @@ +package main + +import ( + "bufio" + "os" + "strconv" + "strings" +) + +func readDataset(path string) { + inFile, _ := os.Open(path) + defer inFile.Close() + scanner := bufio.NewScanner(inFile) + scanner.Split(bufio.ScanLines) + + var lineNum int + for scanner.Scan() { + if lineNum > 0 { + line := strings.Split(scanner.Text(), ",") + var cell CellModel + cell.Radio = line[0] + cell.MCC = line[1] + cell.Net, _ = strconv.Atoi(line[2]) + cell.Area, _ = strconv.Atoi(line[3]) + cell.Cell, _ = strconv.Atoi(line[4]) + cell.Unit, _ = strconv.Atoi(line[5]) + cell.Lon, _ = strconv.ParseFloat(line[6], 64) + cell.Lat, _ = strconv.ParseFloat(line[7], 64) + cell.Range, _ = strconv.ParseFloat(line[8], 64) + cell.Samples, _ = strconv.Atoi(line[9]) + cell.Changeable = line[10] + cell.Created, _ = strconv.ParseInt(line[11], 10, 64) + cell.Updated, _ = strconv.ParseInt(line[12], 10, 64) + cell.AverageSignal, _ = strconv.ParseFloat(line[13], 64) + + //save cell to mongodb + err := cellCollection.Insert(cell) + check(err) + } + lineNum++ + } +} diff --git a/serverConfig.go b/serverConfig.go new file mode 100644 index 0000000..3411e09 --- /dev/null +++ b/serverConfig.go @@ -0,0 +1,69 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "time" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +//server config +type ServerConfig struct { + ServerIP string `json:"serverIP"` + ServerPort string `json:"serverPort"` + AllowedIPs []string `json:"allowedIPs"` + BlockedIPs []string `json:"blockedIPs"` +} + +var serverConfig ServerConfig + +func readServerConfig(path string) { + file, err := ioutil.ReadFile(path) + if err != nil { + fmt.Println("error: ", err) + } + content := string(file) + json.Unmarshal([]byte(content), &serverConfig) +} + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s\t%s\t%s\t%s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + return router +} diff --git a/serverConfig.json b/serverConfig.json new file mode 100644 index 0000000..3cc43f5 --- /dev/null +++ b/serverConfig.json @@ -0,0 +1,8 @@ +{ + "serverIP": "127.0.0.1", + "serverPort": "3017", + "allowedIPs": [ + "127.0.0.1" + ], + "blockedIPs": [] +} diff --git a/serverRoutes.go b/serverRoutes.go new file mode 100644 index 0000000..39aadd6 --- /dev/null +++ b/serverRoutes.go @@ -0,0 +1,46 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "gopkg.in/mgo.v2/bson" +) + +type Routes []Route + +var routes = Routes{ + Route{ + "Index", + "GET", + "/", + Index, + }, + Route{ + "GetAllCells", + "Get", + "/allcells", + GetAllCells, + }, +} + +//ROUTES + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "ask for cells in /r") + //http.FileServer(http.Dir("./web")) +} +func GetAllCells(w http.ResponseWriter, r *http.Request) { + ipFilter(w, r) + + cells := []CellModel{} + iter := cellCollection.Find(bson.M{}).Limit(10000).Iter() + err := iter.All(&cells) + + //convert []cells struct to json + jsonCells, err := json.Marshal(cells) + check(err) + + fmt.Fprintln(w, string(jsonCells)) +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..b636566 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,4 @@ +logs/* +!.gitkeep +node_modules +bower_components diff --git a/web/app.js b/web/app.js new file mode 100644 index 0000000..0b55ebe --- /dev/null +++ b/web/app.js @@ -0,0 +1,19 @@ +'use strict'; + +var urlapi = "http://127.0.0.1:3017/"; + +// Declare app level module which depends on views, and components +angular.module('webApp', [ + 'ngRoute', + 'ngMessages', + 'angularBootstrapMaterial', + 'app.navbar', + 'app.main' +]). +config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { + $locationProvider.hashPrefix('!'); + + $routeProvider.otherwise({ + redirectTo: '/main' + }); + }]); diff --git a/web/bower.json b/web/bower.json new file mode 100644 index 0000000..8133700 --- /dev/null +++ b/web/bower.json @@ -0,0 +1,18 @@ +{ + "name": "cellMapVisualizer", + "description": "cellMapVisualizer", + "version": "0.0.0", + "homepage": "https://github.com/arnaucode/cellMapVisualizer", + "license": "MIT", + "private": true, + "dependencies": { + "angular": "^1.6.2", + "angular-route": "^1.6.1", + "angular-chart.js": "^1.1.1", + "angular-bootstrap-material": "abm#^0.1.4", + "angular-bootstrap": "^2.5.0", + "angular-messages": "^1.6.5", + "components-font-awesome": "^4.7.0", + "ui-leaflet": "^2.0.0" + } +} diff --git a/web/css/colors.css b/web/css/colors.css new file mode 100644 index 0000000..f7f8872 --- /dev/null +++ b/web/css/colors.css @@ -0,0 +1,482 @@ +/* red */ +.c_red50{ + background: #FFEBEE!important; + color: #000000!important; +} +.c_red100{ + background: #FFCDD2!important; + color: #000000!important; +} +.c_red200{ + background: #EF9A9A!important; + color: #000000!important; +} +.c_red300{ + background: #E57373!important; + color: #ffffff!important; +} +.c_red400{ + background: #EF5350!important; + color: #ffffff!important; +} +.c_red500{ + background: #F44336!important; + color: #ffffff!important; +} +.c_red600{ + background: #E53935!important; + color: #ffffff!important; +} +.c_red700{ + background: #D32F2F!important; + color: #ffffff!important; +} +.c_red800{ + background: #C62828!important; + color: #ffffff!important; +} +.c_red900{ + background: #B71C1C!important; + color: #ffffff!important; +} + +.ctext_red400{ + color: #EF5350!important; +} +.ctext_red500{ + color: #F44336!important; +} +.ctext_red600{ + color: #E53935!important; +} + +/* pink */ +.c_pink50{ + background: #FCE4EC!important; + color: #000000!important; +} +.c_pink100{ + background: #F8BBD0!important; + color: #000000!important; +} +.c_pink200{ + background: #F48FB1!important; + color: #000000!important; +} +.c_pink300{ + background: #F06292!important; + color: #ffffff!important; +} +.c_pink400{ + background: #EC407A!important; + color: #ffffff!important; +} +.c_pink500{ + background: #E91E63!important; + color: #ffffff!important; +} +.c_pink600{ + background: #D81B60!important; + color: #ffffff!important; +} +.c_pink700{ + background: #C2185B!important; + color: #ffffff!important; +} +.c_pink800{ + background: #AD1457!important; + color: #ffffff!important; +} +.c_pink900{ + background: #880E4F!important; + color: #ffffff!important; +} + +/* deepPurple */ +.c_deepPurple50{ + background: #EDE7F6!important; + color: #000000!important; +} +.c_deepPurple100{ + background: #D1C4E9!important; + color: #000000!important; +} +.c_deepPurple200{ + background: #B39DDB!important; + color: #000000!important; +} +.c_deepPurple300{ + background: #9575CD!important; + color: #ffffff!important; +} +.c_deepPurple400{ + background: #7E57C2!important; + color: #ffffff!important; +} +.c_deepPurple500{ + background: #673AB7!important; + color: #ffffff!important; +} +.c_deepPurple600{ + background: #5E35B1!important; + color: #ffffff!important; +} +.c_deepPurple700{ + background: #512DA8!important; + color: #ffffff!important; +} +.c_deepPurple800{ + background: #4527A0!important; + color: #ffffff!important; +} +.c_deepPurple900{ + background: #311B92!important; + color: #ffffff!important; +} + +/* indigo */ +.c_indigo50{ + background:#E8EAF6!important; + color: #000000!important; +} +.c_indigo100{ + background:#C5CAE9!important; + color: #000000!important; +} +.c_indigo200{ + background:#9FA8DA!important; + color: #000000!important; +} +.c_indigo300{ + background:#7986CB!important; + color: #ffffff!important; +} +.c_indigo400{ + background:#5C6BC0!important; + color: #ffffff!important; +} +.c_indigo500{ + background:#3F51B5!important; + color: #ffffff!important; +} +.c_indigo600{ + background:#3949AB!important; + color: #ffffff!important; +} +.c_indigo700{ + background:#303F9F!important; + color: #ffffff!important; +} +.c_indigo800{ + background:#283593!important; + color: #ffffff!important; +} +.c_indigo900{ + background:#1A237E!important; + color: #ffffff!important; +} + +.ctext_indigo500{ + color: #3F51B5!important; +} + +/* blue */ +.c_blue50{ + background: #E3F2FD!important; + color: #000000!important; +} +.c_blue100{ + background: #BBDEFB!important; + color: #000000!important; +} +.c_blue200{ + background: #90CAF9!important; + color: #000000!important; +} +.c_blue300{ + background: #64B5F6!important; + color: #ffffff!important; +} +.c_blue400{ + background: #42A5F5!important; + color: #ffffff!important; +} +.c_blue500{ + background: #2196F3!important; + color: #ffffff!important; +} +.c_blue600{ + background: #1E88E5!important; + color: #ffffff!important; +} +.c_blue700{ + background: #1976D2!important; + color: #ffffff!important; +} +.c_blue800{ + background: #1565C0!important; + color: #ffffff!important; +} +.c_blue900{ + background: #0D47A1!important; + color: #ffffff!important; +} + + +/* cyan */ +.c_cyan50{ + background: #E0F7FA!important; + color: #000000!important; +} +.c_cyan100{ + background: #B2EBF2!important; + color: #000000!important; +} +.c_cyan200{ + background: #80DEEA!important; + color: #000000!important; +} +.c_cyan300{ + background: #4DD0E1!important; + color: #ffffff!important; +} +.c_cyan400{ + background: #26C6DA!important; + color: #ffffff!important; +} +.c_cyan500{ + background: #00BCD4!important; + color: #ffffff!important; +} +.c_cyan600{ + background: #00ACC1!important; + color: #ffffff!important; +} +.c_cyan700{ + background: #0097A7!important; + color: #ffffff!important; +} +.c_cyan800{ + background: #00838F!important; + color: #ffffff!important; +} +.c_cyan900{ + background: #006064!important; + color: #ffffff!important; +} + +/* green */ +.c_green50{ + background: #E8F5E9!important; + color: #000000!important; +} +.c_green100{ + background: #C8E6C9!important; + color: #000000!important; +} +.c_green200{ + background: #A5D6A7!important; + color: #000000!important; +} +.c_green300{ + background: #81C784!important; + color: #ffffff!important; +} +.c_green400{ + background: #66BB6A!important; + color: #ffffff!important; +} +.c_green500{ + background: #4CAF50!important; + color: #ffffff!important; +} +.c_green600{ + background: #43A047!important; + color: #ffffff!important; +} +.c_green700{ + background: #388E3C!important; + color: #ffffff!important; +} +.c_green800{ + background: #2E7D32!important; + color: #ffffff!important; +} +.c_green900{ + background: #1B5E20!important; + color: #ffffff!important; +} + +/* yellow */ +.c_yellow50{ + background: #FFFDE7!important; + color: #000000!important; +} +.c_yellow100{ + background: #FFF9C4!important; + color: #000000!important; +} +.c_yellow200{ + background: #FFF59D!important; + color: #000000!important; +} +.c_yellow300{ + background: #FFF176!important; + color: #ffffff!important; +} +.c_yellow400{ + background: #FFEE58!important; + color: #ffffff!important; +} +.c_yellow500{ + background: #FFEB3B!important; + color: #ffffff!important; +} +.c_yellow600{ + background: #FDD835!important; + color: #ffffff!important; +} +.c_yellow700{ + background: #FBC02D!important; + color: #ffffff!important; +} +.c_yellow800{ + background: #F9A825!important; + color: #ffffff!important; +} +.c_yellow900{ + background: #F57F17!important; + color: #ffffff!important; +} + +/* orange */ +.c_orange50{ + background: #FFF3E0!important; + color: #000000!important; +} +.c_orange100{ + background: #FFE0B2!important; + color: #000000!important; +} +.c_orange200{ + background: #FFCC80!important; + color: #000000!important; +} +.c_orange300{ + background: #FFB74D!important; + color: #ffffff!important; +} +.c_orange400{ + background: #FFA726!important; + color: #ffffff!important; +} +.c_orange500{ + background: #FF9800!important; + color: #ffffff!important; +} +.c_orange600{ + background: #FB8C00!important; + color: #ffffff!important; +} +.c_orange700{ + background: #F57C00!important; + color: #ffffff!important; +} +.c_orange800{ + background: #EF6C00!important; + color: #ffffff!important; +} +.c_orange900{ + background: #E65100!important; + color: #ffffff!important; +} + +/* grey */ +.c_grey50{ + background: #FAFAFA!important; + color: #000000!important; +} +.c_grey100{ + background: #F5F5F5!important; + color: #000000!important; +} +.c_grey200{ + background: #EEEEEE!important; + color: #000000!important; +} +.c_grey300{ + background: #E0E0E0!important; + color: #ffffff!important; +} +.c_grey400{ + background: #BDBDBD!important; + color: #ffffff!important; +} +.c_grey500{ + background: #9E9E9E!important; + color: #ffffff!important; +} +.c_grey600{ + background: #757575!important; + color: #ffffff!important; +} +.c_grey700{ + background: #616161!important; + color: #ffffff!important; +} +.c_grey800{ + background: #424242!important; + color: #ffffff!important; +} +.c_grey900{ + background: #212121!important; + color: #ffffff!important; +} + + + +/* blue grey */ +.c_blueGrey50{ + background: #ECEFF1!important; + color: #000000!important; +} +.c_blueGrey100{ + background: #CFD8DC!important; + color: #000000!important; +} +.c_blueGrey200{ + background: #B0BEC5!important; + color: #000000!important; +} +.c_blueGrey300{ + background: #90A4AE!important; + color: #ffffff!important; +} +.c_blueGrey400{ + background: #78909C!important; + color: #ffffff!important; +} +.c_blueGrey500{ + background: #607D8B!important; + color: #ffffff!important; +} +.c_blueGrey600{ + background: #546E7A!important; + color: #ffffff!important; +} +.c_blueGrey700{ + background: #455A64!important; + color: #ffffff!important; +} +.c_blueGrey800{ + background: #37474F!important; + color: #ffffff!important; +} +.c_blueGrey900{ + background: #263238!important; + color: #ffffff!important; +} + +.ctext_blueGrey500{ + color: #607D8B!important; +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..94b5946 --- /dev/null +++ b/web/index.html @@ -0,0 +1,58 @@ + + + + + + + cellMapVisualizer + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..c5e9390 --- /dev/null +++ b/web/package.json @@ -0,0 +1,22 @@ +{ + "name": "cellMapVisualizer", + "private": true, + "version": "0.0.0", + "description": "cellMapVisualizer", + "repository": "https://github.com/arnaucode/cellMapVisualizer", + "license": "MIT", + "devDependencies": { + "bower": "^1.7.7", + "http-server": "^0.9.0" + }, + "scripts": { + "postinstall": "bower install", + "prestart": "npm install", + "start": "http-server -p 8080 -c-1 ./" + }, + "dependencies": { + "bower": "latest", + "connect": "latest", + "serve-static": "latest" + } +} diff --git a/web/views/main/main.html b/web/views/main/main.html new file mode 100644 index 0000000..67f6a57 --- /dev/null +++ b/web/views/main/main.html @@ -0,0 +1,37 @@ +
+
+
+
+
+

Cells

+
+
+ + + + + + + + + + + + + +
MCCArea
{{cell.mcc}}{{cell.area}}
+
+
+
+
+
+
+

Map

+
+
+ +
+
+
+
+
diff --git a/web/views/main/main.js b/web/views/main/main.js new file mode 100644 index 0000000..e180c59 --- /dev/null +++ b/web/views/main/main.js @@ -0,0 +1,53 @@ +'use strict'; + +angular.module('app.main', ['ngRoute', 'ui-leaflet']) + +.config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/main', { + templateUrl: 'views/main/main.html', + controller: 'MainCtrl' + }); +}]) + +.controller('MainCtrl', function($scope, $http) { + //map + $scope.center = {}; + $scope.bounds = {}; + $scope.markers = []; + $scope.paths = []; + $scope.tiles = { + url: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + options: { + attribution: 'OpenStreetMap contributors' + } + }; + + $http.get(urlapi + 'allcells') + .then(function(data) { + console.log('data success'); + console.log(data); + $scope.cells = data.data; + //draw markers on map + $scope.markers = []; + for (var i = 0; i < $scope.cells.length; i++) { + $scope.markers.push({ + lat: Number($scope.cells[i].lat), + lng: Number($scope.cells[i].lon), + message: $scope.cells[i].mcc + }); + $scope.markers.push({ + lat: Number($scope.cells[i].lat), + lng: Number($scope.cells[i].lon), + message: $scope.cells[i].mcc + }); + } + + $scope.center = { + lat: (Number($scope.cells[0].lat) + Number($scope.cells[0].lat)) / 2, + lng: (Number($scope.cells[0].lon) + Number($scope.cells[0].lon)) / 2, + zoom: 4 + }; + }, function(data) { + console.log('data error'); + }); +}); diff --git a/web/views/navbar.html b/web/views/navbar.html new file mode 100644 index 0000000..dab711a --- /dev/null +++ b/web/views/navbar.html @@ -0,0 +1,41 @@ +
+ + +
diff --git a/web/views/navbar.js b/web/views/navbar.js new file mode 100644 index 0000000..3f3ff31 --- /dev/null +++ b/web/views/navbar.js @@ -0,0 +1,18 @@ +'use strict'; + +angular.module('app.navbar', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/navbar', { + templateUrl: 'views/navbar/navbar.html', + controller: 'NavbarCtrl' + }); + }]) + + .controller('NavbarCtrl', function($scope, $http, $routeParams, $location) { + $scope.locationHash = $location.path(); + $scope.goBack = function() { + console.log("goBack"); + window.history.back(); + }; + }); diff --git a/web/webserver.js b/web/webserver.js new file mode 100644 index 0000000..e435559 --- /dev/null +++ b/web/webserver.js @@ -0,0 +1,6 @@ +connect = require('connect'); +var serveStatic = require('serve-static'); +connect().use(serveStatic(__dirname)).listen(3010, function(){ + console.log('Server running on 3010...'); +}); +