initial commit

This commit is contained in:
Blue 2018-08-05 00:46:25 +03:00 committed by Юрий Губич
commit 4b60ece582
327 changed files with 28286 additions and 0 deletions

15
magnus/CMakeLists.txt Normal file
View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.12)
project(magnus)
add_subdirectory(config)
add_subdirectory(lib)
add_subdirectory(middleware)
add_subdirectory(views)
add_subdirectory(test)
add_subdirectory(core)
add_subdirectory(pages)
configure_file(package.json package.json)
configure_file(app.js app.js)
execute_process(COMMAND npm install WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

46
magnus/app.js Normal file
View file

@ -0,0 +1,46 @@
var express = require("express");
var morgan = require("morgan");
var favicon = require("serve-favicon");
var Magnus = require("./core/magnus");
require("./lib/utils/globalMethods");
var config = require("./config");
var log = require("./lib/log")(module);
if (config.get("testing")) {
var Test = require("./test/test");
var test = new Test()
test.run();
test.destructor();
}
var app = express();
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.use(favicon(__dirname + "/public/favicon.ico"));
var httpLog = config.get("httpLog");
if (httpLog) {
app.use(morgan('dev'));
}
app.use(require("./middleware/reply"));
app.use(express.static(__dirname + '/public'));
app.use(require("./middleware/pageInMagnus"));
app.use(require("./middleware/notFound"));
app.use(require("./middleware/errorHandler"));
var server = app.listen(config.get("webServerPort"), "127.0.0.1", function () {
var port = server.address().port;
log.info("Webserver is listening on port " + port);
});
var magnus = global.magnus = new Magnus(config);

View file

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(index.js index.js)
configure_file(config.json config.json)

View file

@ -0,0 +1,9 @@
{
"webServerPort": 3000,
"webSocketServerPort": 8081,
"version": "0.0.2",
"build": "debug",
"httpLog": false,
"testing": true,
"modelDestructionTimeout": 120000
}

8
magnus/config/index.js Normal file
View file

@ -0,0 +1,8 @@
var nconf = require("nconf");
var path = require("path");
nconf.argv()
.env()
.file({file: path.join(__dirname, 'config.json')});
module.exports = nconf;

View file

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(magnus.js magnus.js)
configure_file(commands.js commands.js)
configure_file(connector.js connector.js)

85
magnus/core/commands.js Normal file
View file

@ -0,0 +1,85 @@
"use strict";
var ModelVocabulary = require("../lib/wModel/vocabulary");
var Vocabulary = require("../lib/wType/vocabulary");
var String = require("../lib/wType/string");
var Commands = ModelVocabulary.inherit({
"className": "Commands",
"constructor": function(address) {
ModelVocabulary.fn.constructor.call(this, address);
this._commands = global.Object.create(null);
},
"destructor": function() {
for (var key in this._commands) {
var cmd = this._commands[key];
if (cmd.enabled) {
this._removeHandler(cmd.handler);
}
cmd.name.destructor();
cmd.handler.destructor();
cmd.arguments.destructor();
delete this._commands[key];
}
ModelVocabulary.fn.destructor.call(this);
},
"addCommand": function(key, handler, args) {
if (this._commands[key]) {
throw new Error("Command with this key already exist");
}
this._commands[key] = {
name: new String(key),
handler: handler,
arguments: args,
enabled: false
}
},
"_disableCommand": function(cmd) {
this._removeHandler(cmd.handler);
cmd.enabled = false;
this.erase(cmd.name.toString());
},
"enableCommand": function(key, value) {
var cmd = this._commands[key];
if (!cmd) {
throw new Error("An attempt to access non existing command: " + key);
}
if (cmd.enabled !== value) {
if (value) {
this._enableCommand(cmd);
} else {
this._disableCommand(cmd);
}
}
},
"_enableCommand": function(cmd) {
this._addHandler(cmd.handler);
cmd.enabled = true;
var vc = new Vocabulary();
vc.insert("address", cmd.handler.address.clone());
vc.insert("arguments", cmd.arguments.clone());
this.insert(cmd.name.toString(), vc);
},
"removeCommand": function(name) {
var cmd = this._commands[name];
if (cmd === undefined) {
throw new Error("An attempt to access non existing command: " + key);
}
if (cmd.enabled) {
this._disableCommand(cmd);
}
cmd.name.destructor();
cmd.handler.destructor();
cmd.arguments.destructor();
delete this._commands[name];
}
});
module.exports = Commands;

120
magnus/core/connector.js Normal file
View file

@ -0,0 +1,120 @@
"use strict";
var Subscribable = require("../lib/utils/subscribable");
var Handler = require("../lib/wDispatcher/handler");
var String = require("../lib/wType/string");
var Address = require("../lib/wType/address");
var Uint64 = require("../lib/wType/uint64");
var Object = require("../lib/wType/object");
var Vocabulary = require("../lib/wType/vocabulary");
var Socket = require("../lib/wSocket/socket");
var Connector = Subscribable.inherit({
"className": "Connector",
"constructor": function(dp, srv, cmds) {
Subscribable.fn.constructor.call(this);
this._dispatcher = dp;
this._server = srv;
this._commands = cmds;
this._nodes = global.Object.create(null);
this._ignoredNodes = global.Object.create(null);
this._server.on("newConnection", this._onNewConnection, this);
this._server.on("closedConnection", this._onClosedConnection, this);
var cn = new Address(["connect"]);
var ch = new Handler(this._commands.getAddress()["+"](cn), this, this._h_connect);
var vc = new Vocabulary();
vc.insert("address", new Uint64(Object.objectType.String));
vc.insert("port", new Uint64(Object.objectType.Uint64));
this._commands.addCommand("connect", ch, vc);
this._commands.enableCommand("connect", true);
cn.destructor();
},
"destructor": function() {
this._server.off("newConnection", this._onNewConnection, this);
this._server.off("closedConnection", this._onClosedConnection, this);
this._commands.removeCommand("connect");
for (var key in this._nodes) {
this._commands.removeCommand("disconnect" + key);
}
Subscribable.fn.destructor.call(this);
},
"addIgnoredNode": function(name) {
this._ignoredNodes[name] = true;
},
"sendTo": function(key, event) {
var id = this._nodes[key];
if (!id) {
throw new Error("An attempt to access non existing node in connector");
}
this._server.getConnection(id).send(event);
},
"_onNewConnection": function(socket) {
var name = socket.getRemoteName().toString();
if (this._ignoredNodes[name] === undefined) {
if (this._nodes[name] === undefined) {
if (this._server.getName().toString() === name) {
this.trigger("serviceMessage", "An attempt to connect node to itself, closing connection", 1);
setTimeout(this._server.closeConnection.bind(this._server, socket.getId()));
} else {
var dc = "disconnect";
var dn = dc + name;
var dh = new Handler(this._commands.getAddress()["+"](new Address([dc, name])), this, this._h_disconnect);
this._commands.addCommand(dn, dh, new Vocabulary());
this._commands.enableCommand(dn, true);
this._nodes[name] = socket.getId();
this.trigger("serviceMessage", "New connection, id: " + socket.getId().toString(), 0);
socket.on("message", this._dispatcher.pass, this._dispatcher);
this.trigger("nodeConnected", name);
}
} else {
this.trigger("serviceMessage", "Node " + name + " tried to connect, but connection with that node is already open, closing new connection", 1);
setTimeout(this._server.closeConnection.bind(this._server, socket.getId()));
}
} else {
this.trigger("serviceMessage", "New connection, id: " + socket.getId().toString(), 0);
socket.on("message", this._dispatcher.pass, this._dispatcher);
}
},
"_onClosedConnection": function(socket) {
this.trigger("serviceMessage", "Connection closed, id: " + socket.getId().toString());
var name = socket.getRemoteName().toString();
if (this._ignoredNodes[name] === undefined) {
if (this._nodes[name]) {
this._commands.removeCommand("disconnect" + name);
delete this._nodes[name];
this.trigger("nodeDisconnected", name);
}
}
},
"getNodeSocket": function(key) {
var id = this._nodes[key];
if (!id) {
throw new Error("An attempt to access non existing node in connector");
}
return this._server.getConnection(id);
},
"_h_connect": function(ev) {
var vc = ev.getData();
this._server.openConnection(vc.at("address"), vc.at("port"));
},
"_h_disconnect": function(ev) {
var addr = ev.getDestination();
var id = this._nodes[addr.back().toString()];
if (id) {
this._server.closeConnection(id);
}
}
});
module.exports = Connector;

153
magnus/core/magnus.js Normal file
View file

@ -0,0 +1,153 @@
"use strict";
var Subscribable = require("../lib/utils/subscribable");
var Socket = require("../lib/wSocket/socket");
var Server = require("../lib/wSocket/server");
var Address = require("../lib/wType/address");
var String = require("../lib/wType/string");
var Vocabulary = require("../lib/wType/vocabulary");
var Dispatcher = require("../lib/wDispatcher/dispatcher");
var ParentReporter = require("../lib/wDispatcher/parentreporter");
var Logger = require("../lib/wDispatcher/logger");
var log = require("../lib/log")(module);
var Commands = require("./commands");
var Connector = require("./connector");
var GlobalControls = require("../lib/wModel/globalControls");
var PageStorage = require("../lib/wModel/pageStorage");
var ModelString = require("../lib/wModel/string");
var Attributes = require("../lib/wModel/attributes");
var HomePage = require("../pages/home");
var MusicPage = require("../pages/music");
var TestPage = require("../pages/test");
var Magnus = Subscribable.inherit({
"className": "Magnus",
"constructor": function(config) {
Subscribable.fn.constructor.call(this);
this._cfg = config;
this._initDispatcher();
this._initServer();
this._initModels();
this._initConnector();
this._initPages();
var port = this._cfg.get("webSocketServerPort");
this.server.listen(port);
global.magnus = this;
},
"_initConnector": function() {
this._connector = new Connector(this.dispatcher, this.server, this._commands);
this._connector.on("serviceMessage", this._onModelServiceMessage, this);
this._connector.on("nodeConnected", this._onNodeConnected, this);
this._connector.on("nodeDisconnected", this._onNodeDisconnected, this);
this._connector.addIgnoredNode("Lorgar");
this._connector.addIgnoredNode("Roboute");
},
"_initDispatcher": function() {
this.dispatcher = new Dispatcher();
this._logger = new Logger();
this._pr = new ParentReporter();
this.dispatcher.registerDefaultHandler(this._pr);
this.dispatcher.registerDefaultHandler(this._logger);
},
"_initModels": function() {
this._commands = new Commands(new Address(["management"]));
var version = new ModelString(new Address(["version"]), this._cfg.get("version"));
version.addProperty("backgroundColor","secondaryColor");
version.addProperty("color", "secondaryFontColor");
version.addProperty("fontFamily", "smallFont");
version.addProperty("fontSize", "smallFontSize");
this._attributes = new Attributes(new Address(["attributes"]));
this._gc = new GlobalControls(new Address(["magnus", "gc"]));
var root = this._rootPage = new HomePage(new Address(["pages", "root"]), "root");
this._ps = new PageStorage(new Address(["magnus", "ps"]), root, this._pr);
this._commands.on("serviceMessage", this._onModelServiceMessage, this);
this._gc.on("serviceMessage", this._onModelServiceMessage, this);
this._ps.on("serviceMessage", this._onModelServiceMessage, this);
this._attributes.on("serviceMessage", this._onModelServiceMessage, this);
this._attributes.addAttribute("name", new ModelString(new Address(["attributes", "name"]), "Magnus"));
this._attributes.addAttribute("connectionsAmount", new ModelString(new Address(["connectionsAmount"]), "0"));
this._attributes.addAttribute("version", version);
this._gc.addModelAsLink("version", version);
this._commands.register(this.dispatcher, this.server);
this._gc.register(this.dispatcher, this.server);
this._ps.register(this.dispatcher, this.server);
this._attributes.register(this.dispatcher, this.server);
},
"_initPages": function() {
this._gc.addNav("Home", this._rootPage.getAddress());
var music = this._musicPage = new MusicPage(new Address(["pages", "/music"]), "music");
this._rootPage.addPage(music);
this._gc.addNav("Music", music.getAddress());
var test = new TestPage(new Address(["pages", "/test"]), "test");
this._rootPage.addPage(test);
this._gc.addNav("Testing...", test.getAddress());
},
"_initServer": function() {
this.server = new Server("Magnus");
this.server.on("ready", this._onServerReady, this);
this.server.on("connectionsCountChange", this._onConnectionsCountChange, this);
},
"hasPage": function(name) {
return this._ps.hasPage(name);
},
"_onConnectionsCountChange": function(count) {
this._attributes.setAttribute("connectionsAmount", count);
},
"_onModelServiceMessage": function(msg, severity) {
var fn;
switch (severity) {
case 2:
fn = log.error;
break;
case 1:
fn = log.warn;
break;
case 0:
default:
fn = log.info;
break;
}
fn(msg);
},
"_onNodeConnected": function(nodeName) {
switch (nodeName) {
case "Perturabo":
this._musicPage.showBandList(this._connector.getNodeSocket(nodeName));
break;
case "Corax":
break;
}
},
"_onNodeDisconnected": function(nodeName) {
switch (nodeName) {
case "Perturabo":
this._musicPage.showError();
break;
case "Corax":
break;
}
},
"_onServerReady": function() {
log.info("Magnus is listening on port " + this._cfg.get("webSocketServerPort"));
log.info("Magnus is ready");
}
});
module.exports = Magnus;

13
magnus/lib/CMakeLists.txt Normal file
View file

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 2.8.12)
add_subdirectory(wSocket)
add_subdirectory(utils)
add_subdirectory(wDispatcher)
add_subdirectory(wType)
add_subdirectory(wContainer)
add_subdirectory(wController)
add_subdirectory(wTest)
add_subdirectory(wModel)
configure_file(log.js log.js)
configure_file(httpError.js httpError.js)

15
magnus/lib/httpError.js Normal file
View file

@ -0,0 +1,15 @@
"use strict";
var http = require("http");
class HttpError extends Error
{
constructor(status, message) {
super(status, message);
Error.captureStackTrace(this, HttpError);
this.status = status;
this.message = message || http.STATUS_CODES[status] || "Error";
}
}
module.exports = HttpError;

18
magnus/lib/log.js Normal file
View file

@ -0,0 +1,18 @@
var Winston = require("winston");
var config = require("../config");
var ENV = config.get('build');
function getLogger(module) {
var path = module.filename.split('/').slice(-2).join('/');
return new Winston.Logger({
transports: [
new Winston.transports.Console({
colorize: true,
level: ENV == 'debug' ? 'debug' : 'error'
})
]
});
}
module.exports = getLogger;

View file

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(utils/class.js lib/utils/class ${MAGNUS_DIR} node)
add_jslib(utils/subscribable.js lib/utils/subscribable ${MAGNUS_DIR} node)
add_jslib(utils/globalMethods.js lib/utils/globalMethods ${MAGNUS_DIR} node)

View file

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wContainer/abstractmap.js lib/wContainer/abstractmap ${MAGNUS_DIR} node)
add_jslib(wContainer/abstractlist.js lib/wContainer/abstractlist ${MAGNUS_DIR} node)
add_jslib(wContainer/abstractorder.js lib/wContainer/abstractorder ${MAGNUS_DIR} node)
add_jslib(wContainer/abstractpair.js lib/wContainer/abstractpair ${MAGNUS_DIR} node)
add_jslib(wContainer/abstractset.js lib/wContainer/abstractset ${MAGNUS_DIR} node)

View file

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wController/list.js lib/wController/list ${MAGNUS_DIR} node)
add_jslib(wController/controller.js lib/wController/controller ${MAGNUS_DIR} node)
add_jslib(wController/vocabulary.js lib/wController/vocabulary ${MAGNUS_DIR} node)
add_jslib(wController/catalogue.js lib/wController/catalogue ${MAGNUS_DIR} node)

View file

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wDispatcher/dispatcher.js lib/wDispatcher/dispatcher ${MAGNUS_DIR} node)
add_jslib(wDispatcher/defaulthandler.js lib/wDispatcher/defaulthandler ${MAGNUS_DIR} node)
add_jslib(wDispatcher/handler.js lib/wDispatcher/handler ${MAGNUS_DIR} node)
add_jslib(wDispatcher/logger.js lib/wDispatcher/logger ${MAGNUS_DIR} node)
add_jslib(wDispatcher/parentreporter.js lib/wDispatcher/parentreporter ${MAGNUS_DIR} node)

View file

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wModel/globalControls.js lib/wModel/globalControls ${MAGNUS_DIR} node)
add_jslib(wModel/link.js lib/wModel/link ${MAGNUS_DIR} node)
add_jslib(wModel/list.js lib/wModel/list ${MAGNUS_DIR} node)
add_jslib(wModel/model.js lib/wModel/model ${MAGNUS_DIR} node)
add_jslib(wModel/page.js lib/wModel/page ${MAGNUS_DIR} node)
add_jslib(wModel/pageStorage.js lib/wModel/pageStorage ${MAGNUS_DIR} node)
add_jslib(wModel/panesList.js lib/wModel/panesList ${MAGNUS_DIR} node)
add_jslib(wModel/string.js lib/wModel/string ${MAGNUS_DIR} node)
add_jslib(wModel/theme.js lib/wModel/theme ${MAGNUS_DIR} node)
add_jslib(wModel/themeStorage.js lib/wModel/themeStorage ${MAGNUS_DIR} node)
add_jslib(wModel/vocabulary.js lib/wModel/vocabulary ${MAGNUS_DIR} node)
add_jslib(wModel/attributes.js lib/wModel/attributes ${MAGNUS_DIR} node)
add_jslib(wModel/image.js lib/wModel/image ${MAGNUS_DIR} node)
add_subdirectory(proxy)

View file

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wModel/proxy/proxy.js lib/wModel/proxy/proxy ${MAGNUS_DIR} node)
add_jslib(wModel/proxy/list.js lib/wModel/proxy/list ${MAGNUS_DIR} node)
add_jslib(wModel/proxy/vocabulary.js lib/wModel/proxy/vocabulary ${MAGNUS_DIR} node)
add_jslib(wModel/proxy/catalogue.js lib/wModel/proxy/catalogue ${MAGNUS_DIR} node)
configure_file(pane.js pane.js)

View file

@ -0,0 +1,32 @@
"use strict";
var MVocabulary = require("./vocabulary");
var Address = require("../../wType/address");
var Boolean = require("../../wType/boolean");
var Pane = MVocabulary.inherit({
"className": "Pane",
"constructor": function(address, controllerAddress, socket) {
MVocabulary.fn.constructor.call(this, address, controllerAddress, socket);
if (this.constructor.pageAddress) {
this.hasPageLink = true;
var id = address.back();
this._pageLink = this.constructor.pageAddress["+"](new Address([id.toString()]));
}
},
"_getAllData": function() {
var vc = this.controller.data.clone();
vc.insert("hasPageLink", new Boolean(this.hasPageLink));
if (this.hasPageLink) {
vc.insert("pageLink", this._pageLink.clone());
}
return vc;
}
});
module.exports = Pane;

View file

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(socket.js socket.js)
configure_file(server.js server.js)

View file

@ -0,0 +1,154 @@
"use strict";
var WebSocketServer = require("ws").Server;
var Socket = require("./socket");
var Subscribable = require("../utils/subscribable");
var AbstractMap = require("../wContainer/abstractmap");
var AbstractSet = require("../wContainer/abstractset");
var String = require("../wType/string");
var Uint64 = require("../wType/uint64");
var Server = Subscribable.inherit({
"className": "Server",
"constructor": function(name) {
if (!name) {
throw new Error("Can't construct a socket without a name");
}
Subscribable.fn.constructor.call(this);
this._lastId = new Uint64(0);
this._pool = new Server.Uint64Set(true);
this._name = name instanceof String ? name : new String(name);
this._server = undefined;
this._connections = new Server.ConnectionsMap(true);
this._listening = false;
this._initProxy();
},
"destructor": function() {
if (this._listening) {
this._server.stop();
delete this._server;
}
this._lastId.destructor();
this._pool.destructor();
this._name.destructor();
this._connections.destructor();
Subscribable.fn.destructor.call(this);
},
"getName": function() {
return this._name;
},
"listen": function(port) {
if (!this._listening) {
this._listening = true;
this._server = new WebSocketServer({port: port}, this._proxy.onReady);
this._server.on("connection", this._proxy.onConnection);
}
},
"stop": function() {
if (this._listening) {
this._listening = false;
this._server.stop();
this._lastId = new Uint64(0);
this._connections.clear();
this._pool.clear();
delete this._server;
}
},
"getConnection": function(id) {
var itr = this._connections.find(id);
if (itr["=="](this._connections.end())) {
throw new Error("Connection not found");
}
return itr["*"]().second;
},
"getConnectionsCount": function() {
return this._connections.size();
},
"openConnection": function(addr, port) {
var webSocket = new Subscribable();
var wSocket = this._createSocket(webSocket);
wSocket._socket.destructor();
wSocket.open(addr, port);
},
"closeConnection": function(id) {
var itr = this._connections.find(id);
if (itr["=="](this._connections.end())) {
throw new Error("Connection not found");
}
itr["*"]().second.close();
},
"_createSocket": function(socket) {
var connectionId;
if (this._pool.size() === 0) {
this._lastId["++"]()
connectionId = this._lastId.clone();
} else {
var itr = this._pool.begin();
connectionId = itr["*"]().clone();
this._pool.erase(itr);
}
var wSocket = new Socket(this._name, socket, connectionId);
this._connections.insert(connectionId, wSocket);
wSocket.on("connected", this._onSocketConnected.bind(this, wSocket));
wSocket.on("disconnected", this._onSocketDisconnected.bind(this, wSocket));
wSocket.on("negotiationId", this._onSocketNegotiationId.bind(this, wSocket));
return wSocket;
},
"_initProxy": function() {
this._proxy = {
onConnection: this._onConnection.bind(this),
onReady: this._onReady.bind(this)
};
},
"_onConnection": function(socket) {
var wSocket = this._createSocket(socket);
wSocket._setRemoteId();
},
"_onReady": function() {
this.trigger("ready");
},
"_onSocketConnected": function(socket) {
this.trigger("newConnection", socket);
this.trigger("connectionCountChange", this._connections.size());
},
"_onSocketDisconnected": function(socket) {
var cItr = this._connections.find(socket.getId());
this._pool.insert(socket.getId().clone());
this.trigger("closedConnection", socket);
this.trigger("connectionCountChange", this._connections.size());
setTimeout(this._connections.erase.bind(this._connections, cItr), 1);
},
"_onSocketNegotiationId": function(socket, id) {
var oldId = socket.getId();
if (id["=="](oldId)) {
socket._setRemoteName();
} else {
var pItr = this._pool.lowerBound(id);
var newId;
if (pItr["=="](this._pool.end())) {
this._lastId["++"]();
newId = this._lastId.clone();
} else {
newId = pItr["*"]().clone();
this._pool.erase(pItr);
}
var itr = this._connections.find(oldId);
itr["*"]().second = undefined; //to prevent autodestruction of the socket;
this._connections.erase(itr);
this._pool.insert(oldId);
socket._id = newId;
this._connections.insert(newId.clone(), socket);
socket._setRemoteId();
}
}
});
Server.ConnectionsMap = AbstractMap.template(Uint64, Socket);
Server.Uint64Set = AbstractSet.template(Uint64);
module.exports = Server;

View file

@ -0,0 +1,217 @@
"use strict";
var WebSocket = require("ws");
var Subscribable = require("../utils/subscribable");
var Event = require("../wType/event");
var ByteArray = require("../wType/bytearray");
var String = require("../wType/string");
var Vocabulary = require("../wType/vocabulary");
var Uint64 = require("../wType/uint64");
var Address = require("../wType/address");
var factory = require("../wType/factory");
var Socket = Subscribable.inherit({
"className": "Socket",
"constructor": function(name, socket, id) {
if (!name) {
throw new Error("Can't construct a socket without a name");
}
Subscribable.fn.constructor.call(this);
this._state = DISCONNECTED;
this._dState = SIZE;
this._name = name instanceof String ? name : new String(name);
this._remoteName = new String();
this._id = new Uint64(0);
this._serverCreated = false;
this._helperBuffer = new ByteArray(4);
this._initProxy();
if (socket) {
this._serverCreated = true;
this._socket = socket;
this._id.destructor();
this._id = id.clone();
this._socket.on("close", this._proxy.onClose);
this._socket.on("error", this._proxy.onError);
this._socket.on("message", this._proxy.onMessage);
}
},
"destructor": function() {
this.close();
if (this._state === DISCONNECTING) {
var onclose = function() {
Subscribable.fn.destructor.call(this);
}
this.on("disconnected", onclose.bind(this));
} else {
Subscribable.fn.destructor.call(this);
}
},
"close": function() {
if ((this._state !== DISCONNECTED) && (this._state !== DISCONNECTING)) {
this._state = DISCONNECTING;
this._socket.close();
}
},
"getId": function() {
return this._id;
},
"getRemoteName": function() {
return this._remoteName;
},
"_initProxy": function() {
this._proxy = {
onClose: this._onClose.bind(this),
onError: this._onError.bind(this),
onMessage: this._onMessage.bind(this)
};
},
"isOpened": function() {
return this._state !== undefined && this._state === CONNECTED;
},
"_onClose": function(ev) {
this._state = DISCONNECTED;
this.trigger("disconnected", ev, this);
},
"_onError": function(err) {
this.trigger("error", err);
},
"_onEvent": function(ev) {
if (ev.isSystem()) {
var cmd = ev._data.at("command").toString();
switch(cmd) {
case "setId":
if (this._serverCreated) {
if (this._state === CONNECTING) {
this.trigger("negotiationId", ev._data.at("id"));
} else {
throw new Error("An attempt to set id in unexpected time");
}
} else {
this._setId(ev._data.at("id"));
this._setRemoteName();
}
break;
case "setName":
this._setName(ev._data.at("name"));
if (!ev._data.at("yourName")["=="](this._name)) {
this._setRemoteName();
}
this._state = CONNECTED;
this.trigger("connected");
break;
default:
throw new Error("Unknown system command: " + cmd);
}
} else {
this.trigger("message", ev);
}
ev.destructor();
},
"_onMessage": function(msg) {
var raw = new Uint8Array(msg);
var i = 0;
while (i < raw.length) {
switch (this._dState) {
case SIZE:
i = this._helperBuffer.fill(raw, raw.length, i);
if (this._helperBuffer.filled()) {
var size = this._helperBuffer.pop32();
this._helperBuffer.destructor();
this._helperBuffer = new ByteArray(size + 1);
this._dState = BODY;
}
break;
case BODY:
i = this._helperBuffer.fill(raw, raw.length, i);
if (this._helperBuffer.filled()) {
var ev = factory(this._helperBuffer);
this._onEvent(ev);
this._helperBuffer.destructor();
this._helperBuffer = new ByteArray(4);
this._dState = SIZE;
}
break;
}
}
},
"open": function(addr, port) {
if (this._state === DISCONNECTED) {
this._state = CONNECTING;
this._remoteName.destructor();
this._remoteName = new String();
this._socket = new WebSocket("ws://"+ addr + ":" + port);
this._socket.on("close", this._proxy.onClose);
this._socket.on("error", this._proxy.onError);
this._socket.on("message", this._proxy.onMessage);
}
},
"send": function(ev) {
var size = ev.size();
var ba = new ByteArray(size + 5);
ba.push32(size);
ba.push8(ev.getType());
ev.serialize(ba);
this._socket.send(ba.data().buffer);
},
"_setId": function(id) {
if (this._state === CONNECTING) {
this._id.destructor();
this._id = id.clone();
} else {
throw new Error("An attempt to set id in unexpected time");
}
},
"_setName": function(name) {
if ((this._state === CONNECTING) && (this._id.valueOf() !== 0)) {
this._remoteName.destructor();
this._remoteName = name.clone();
} else {
throw new Error("An attempt to set name in unexpected time");
}
},
"_setRemoteName": function() {
var vc = new Vocabulary();
vc.insert("command", new String("setName"));
vc.insert("name", this._name.clone());
vc.insert("yourName", this._remoteName.clone());
var ev = new Event(new Address(), vc, true);
ev.setSenderId(this._id.clone());
this.send(ev);
ev.destructor();
},
"_setRemoteId": function() {
if (this._state === DISCONNECTED) {
this._state = CONNECTING;
}
var vc = new Vocabulary();
vc.insert("command", new String("setId"));
vc.insert("id", this._id.clone());
var ev = new Event(new Address(), vc, true);
ev.setSenderId(this._id.clone());
this.send(ev);
ev.destructor();
}
});
var DISCONNECTED = 111;
var DISCONNECTING = 110;
var CONNECTING = 101;
var CONNECTED = 100;
var SIZE = 1
var BODY = 10;
module.exports = Socket;

View file

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wTest/test.js lib/wTest/test ${MAGNUS_DIR} node)
add_jslib(wTest/abstractmap.js lib/wTest/abstractmap ${MAGNUS_DIR} node)
add_jslib(wTest/abstractlist.js lib/wTest/abstractlist ${MAGNUS_DIR} node)
add_jslib(wTest/abstractorder.js lib/wTest/abstractorder ${MAGNUS_DIR} node)
add_jslib(wTest/uint64.js lib/wTest/uint64 ${MAGNUS_DIR} node)

View file

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 2.8.12)
add_jslib(wType/address.js lib/wType/address ${MAGNUS_DIR} node)
add_jslib(wType/boolean.js lib/wType/boolean ${MAGNUS_DIR} node)
add_jslib(wType/bytearray.js lib/wType/bytearray ${MAGNUS_DIR} node)
add_jslib(wType/event.js lib/wType/event ${MAGNUS_DIR} node)
add_jslib(wType/object.js lib/wType/object ${MAGNUS_DIR} node)
add_jslib(wType/string.js lib/wType/string ${MAGNUS_DIR} node)
add_jslib(wType/uint64.js lib/wType/uint64 ${MAGNUS_DIR} node)
add_jslib(wType/vector.js lib/wType/vector ${MAGNUS_DIR} node)
add_jslib(wType/vocabulary.js lib/wType/vocabulary ${MAGNUS_DIR} node)
add_jslib(wType/blob.js lib/wType/blob ${MAGNUS_DIR} node)
add_jslib(wType/factory.js lib/wType/factory ${MAGNUS_DIR} node)

View file

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(errorHandler.js errorHandler.js)
configure_file(reply.js reply.js)
configure_file(notFound.js notFound.js)
configure_file(pageInMagnus.js pageInMagnus.js)

View file

@ -0,0 +1,36 @@
var defaultHandler = require("errorhandler");
var config = require("../config");
var log = require("../lib/log");
var HttpError = require("../lib/httpError");
function errorHandler(err, req, res, next) {
if (typeof err == "number") {
err = new HttpError(err);
}
if (err instanceof HttpError) {
sendHttpError(err, res, req);
} else {
if (config.get("build") === "debug") {
var handler = defaultHandler();
handler(err, req, res, next);
} else {
log.error(err);
err = new HttpError(500);
sendHttpError(err, res, req);
}
}
}
function sendHttpError(error, res, req) {
res.status(error.status);
//if (req.headers['x-requested-with'] == 'XMLHttpRequest') {
// res.json(error);
//} else {
// res.reply(error);
//}
res.reply(error);
}
module.exports = errorHandler;

View file

@ -0,0 +1,6 @@
"use strict";
var HttpError = require("../lib/httpError");
module.exports = function(req, res, next) {
return next(new HttpError(404, 'Page not found!'));
};

View file

@ -0,0 +1,9 @@
"use strict";
module.exports = function(req, res, next) {
if (global.magnus.hasPage(req.path)) {
res.reply("Building " + req.path + "...");
} else {
next();
}
};

View file

@ -0,0 +1,8 @@
"use strict";
var path = require("path");
module.exports = function(req, res, next) {
res.reply = function(info) {
this.render("index", {info: info});
};
next();
};

20
magnus/package.json Normal file
View file

@ -0,0 +1,20 @@
{
"name": "magnus",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "*",
"async": "*",
"winston": "*",
"morgan": "*",
"nconf": "*",
"errorhandler": "*",
"serve-favicon": "*",
"jade": "*",
"ws": "*",
"bintrees": "*"
}
}

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(music.js music.js)
configure_file(home.js home.js)
configure_file(test.js test.js)
configure_file(list.js list.js)
configure_file(tempPage.js tempPage.js)
configure_file(artist.js artist.js)
configure_file(album.js album.js)
configure_file(song.js song.js)

144
magnus/pages/album.js Normal file
View file

@ -0,0 +1,144 @@
"use strict";
var TempPage = require("./tempPage");
var String = require("../lib/wModel/string");
var ProxyCatModel = require("../lib/wModel/proxy/catalogue");
var PaneModel = require("../lib/wModel/proxy/pane");
var Image = require("../lib/wModel/image");
var Model = require("../lib/wModel/model");
var VCController = require("../lib/wController/vocabulary");
var Address = require("../lib/wType/address");
var Uint64 = require("../lib/wType/uint64");
var Vocabulary = require("../lib/wType/vocabulary");
var AlbumPage = TempPage.inherit({
"className": "AlbumPage",
"constructor": function(address, name, id, proxySocket) {
TempPage.fn.constructor.call(this, address, name);
this._remoteId = id;
this._proxySocket = proxySocket;
this._ctrls = Object.create(null);
this._image = new Image(this._address["+"](new Address(["image"])), new Uint64(0));
var imageOptions = new Vocabulary();
imageOptions.insert("minWidth", new Uint64(200));
imageOptions.insert("maxWidth", new Uint64(200));
imageOptions.insert("minHeight", new Uint64(200));
imageOptions.insert("maxHeight", new Uint64(200));
this.addItem(this._image, 0, 0, 2, 1, TempPage.Aligment.CenterCenter, new Uint64(TempPage.getModelTypeId(this._image)), imageOptions);
var header = this._header = new String(this._address["+"](new Address(["header"])), "");
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 1, 1, 1, TempPage.Aligment.LeftTop);
var artist = this._artist = new String(this._address["+"](new Address(["artist"])), "Artist name");
artist.addProperty("fontFamily", "casualFont");
this.addItem(artist, 1, 1, 1, 1, TempPage.Aligment.LeftTop);
var spacer = new Model(this._address["+"](new Address(["spacer"])));
this.addItem(spacer, 0, 2, 2, 1);
this._songs = new ProxyCatModel(
this._address["+"](new Address(["songs"])),
new Address(["songs"]),
{
sorting: {ascending: true, field: "name"},
filter: {album: id.clone()}
},
proxySocket
);
this._songs.className = "PanesList";
var PaneClass = PaneModel.Songs;
this._songs.setChildrenClass(PaneClass);
this.addItem(this._songs, 2, 0, 1, 3, TempPage.Aligment.CenterTop);
},
"destructor": function() {
this._clearCtrls();
TempPage.fn.destructor.call(this);
},
"_clearCtrls": function() {
for (var key in this._ctrls) {
this._ctrls[key].destructor();
}
this._ctrls = Object.create(null);
},
"_onAlbumNewElement": function(key, el) {
switch(key) {
case "name":
this._header.set(el);
break;
case "image":
this._image.set(el.clone());
break;
case "artist":
var arVC = new VCController(new Address(["artists", el.toString()]));
arVC.on("newElement", this._onArtistNewElement, this);
arVC.on("removeElement", this._onArtistRemoveElement, this);
this._ctrls.artist = arVC;
arVC.register(this._dp, this._proxySocket);
arVC.subscribe();
break;
}
},
"_onAlbumRemoveElement": function(key) {
switch(key) {
case "name":
this._header.set("");
break;
case "image":
this._image.set(new Uint64(0));
break;
case "artist":
this._artist.set("");
this._ctrls.artist.destructor();
delete this._ctrls.artist;
}
},
"_onArtistNewElement": function(key, el) {
switch(key) {
case "name":
this._artist.set(el);
break;
}
},
"_onArtistRemoveElement": function(key) {
switch(key) {
case "name":
this._artist.set("unknown");
}
},
"register": function(dp, server) {
TempPage.fn.register.call(this, dp, server);
for (var key in this._ctrls) {
this._ctrls[key].register(dp, this._proxySocket);
}
},
"setParentReporter": function(pr) {
TempPage.fn.setParentReporter.call(this, pr);
this._pr.registerParent(this._songs.getAddress(), this._songs.reporterHandler);
this._songs.subscribe();
var albumVC = new VCController(new Address(["albums", this._remoteId.toString()]));
albumVC.on("newElement", this._onAlbumNewElement, this);
albumVC.on("removeElement", this._onAlbumRemoveElement, this);
this._ctrls.album = albumVC;
albumVC.register(this._dp, this._proxySocket);
albumVC.subscribe();
},
"unsetParentReporter": function() {
this._pr.unregisterParent(this._songs.getAddress());
this._clearCtrls();
TempPage.fn.unsetParentReporter.call(this);
}
});
module.exports = AlbumPage;

112
magnus/pages/artist.js Normal file
View file

@ -0,0 +1,112 @@
"use strict";
var TempPage = require("./tempPage");
var String = require("../lib/wModel/string");
var ProxyCatModel = require("../lib/wModel/proxy/catalogue");
var PaneModel = require("../lib/wModel/proxy/pane");
var VCController = require("../lib/wController/vocabulary");
var Address = require("../lib/wType/address");
var ArtistPage = TempPage.inherit({
"className": "ArtistPage",
"constructor": function(address, name, id, proxySocket) {
TempPage.fn.constructor.call(this, address, name);
this._remoteId = id;
this._proxySocket = proxySocket;
this._ctrls = Object.create(null);
var header = this._header = new String(this._address["+"](new Address(["header"])), "");
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 0, 1, 1, TempPage.Aligment.CenterTop);
this._albums = new ProxyCatModel(
this._address["+"](new Address(["albums"])),
new Address(["albums"]),
{
sorting: {ascending: true, field: "name"},
filter: {artist: id.clone()}
},
proxySocket
);
this._albums.className = "PanesList";
var PaneClass = PaneModel.Albums;
this._albums.setChildrenClass(PaneClass);
this.addItem(this._albums, 1, 0, 1, 1, TempPage.Aligment.CenterTop);
this._songs = new ProxyCatModel(
this._address["+"](new Address(["songs"])),
new Address(["songs"]),
{
sorting: {ascending: true, field: "name"},
filter: {artist: id.clone()}
},
proxySocket
);
this._songs.className = "PanesList";
var PaneClass = PaneModel.Songs;
this._songs.setChildrenClass(PaneClass);
this.addItem(this._songs, 2, 0, 1, 1, TempPage.Aligment.CenterTop);
},
"destructor": function() {
this._clearCtrls();
TempPage.fn.destructor.call(this);
},
"_clearCtrls": function() {
for (var key in this._ctrls) {
this._ctrls[key].destructor();
}
this._ctrls = Object.create(null);
},
"_onArtistNewElement": function(key, el) {
switch(key) {
case "name":
this._header.set(el);
break;
}
},
"_onArtistRemoveElement": function(key) {
switch(key) {
case "name":
this._header.set("");
break;
}
},
"register": function(dp, server) {
TempPage.fn.register.call(this, dp, server);
for (var key in this._ctrls) {
this._ctrls[key].register(dp, this._proxySocket);
}
},
"setParentReporter": function(pr) {
TempPage.fn.setParentReporter.call(this, pr);
this._pr.registerParent(this._albums.getAddress(), this._albums.reporterHandler);
this._pr.registerParent(this._songs.getAddress(), this._songs.reporterHandler);
this._albums.subscribe()
this._songs.subscribe();
var artistVC = new VCController(new Address(["artists", this._remoteId.toString()]));
artistVC.on("newElement", this._onArtistNewElement, this);
artistVC.on("removeElement", this._onArtistRemoveElement, this);
this._ctrls.artist = artistVC;
artistVC.register(this._dp, this._proxySocket);
artistVC.subscribe();
},
"unsetParentReporter": function() {
this._pr.unregisterParent(this._albums.getAddress());
this._pr.unregisterParent(this._songs.getAddress());
this._clearCtrls();
TempPage.fn.unsetParentReporter.call(this);
}
});
module.exports = ArtistPage;

19
magnus/pages/home.js Normal file
View file

@ -0,0 +1,19 @@
"use strict";
var Page = require("../lib/wModel/page");
var String = require("../lib/wModel/string");
var Address = require("../lib/wType/address");
var HomePage = Page.inherit({
"className": "HomePage",
"constructor": function(address, name) {
Page.fn.constructor.call(this, address, name);
var header = new String(this._address["+"](new Address(["message"])), "This is the root page");
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop);
}
});
module.exports = HomePage;

115
magnus/pages/list.js Normal file
View file

@ -0,0 +1,115 @@
"use strict";
var Page = require("../lib/wModel/page");
var String = require("../lib/wModel/string");
var ProxyCatModel = require("../lib/wModel/proxy/catalogue");
var PaneModel = require("../lib/wModel/proxy/pane");
var Address = require("../lib/wType/address");
var Uint64 = require("../lib/wType/uint64");
var Handler = require("../lib/wDispatcher/handler");
var List = Page.inherit({
"className": "ListPage",
"constructor": function(address, name, remoteAddress, socket, ChildClass) {
Page.fn.constructor.call(this, address, name);
this._proxySocket = socket;
this._ChildClass = ChildClass;
var header = new String(this._address["+"](new Address(["header"])), name);
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop);
this._list = new ProxyCatModel(
this._address["+"](new Address(["list"])),
remoteAddress,
{
sorting: {ascending: true, field: "name"}
},
socket
);
this._list.className = "PanesList";
var PaneClass = PaneModel[name];
if (!PaneClass) {
PaneClass = PaneModel.inherit({});
PaneClass.pageAddress = address;
}
this._list.setChildrenClass(PaneClass);
this.addItem(this._list, 1, 0, 1, 1, Page.Aligment.CenterTop);
this._reporterHandler = new Handler(this._address["+"](new Address(["subscribeMember"])), this, this._h_subscribeMember);
},
"destructor": function() {
this._reporterHandler.destructor();
this.removeItem(this._list);
this._list.destructor();
Page.fn.destructor.call(this);
},
"_createChildPage": function(id) {
var childName = id.toString();
var postfix = new Address([childName]);
var childAddr = this._address["+"](postfix);
var child = new this._ChildClass(childAddr, childName, id.clone(), this._proxySocket);
this.addPage(child);
child.on("destroyMe", this._destroyChild.bind(this, child)); //to remove model if it has no subscribers
child.checkSubscribersAndDestroy();
return child;
},
"_destroyChild": function(child) {
this.removePage(child);
child.destructor();
},
"getChildPage": function(name) {
var child = this._childPages[name];
if (child === undefined) {
var int = parseInt(name);
if (int == name) {
var id = new Uint64(int);
var itr = this._list.controller.data.find(id);
if (!itr["=="](this._list.controller.data.end())) {
child = this._createChildPage(id);
}
}
}
return child;
},
"_h_subscribeMember": function(ev) {
var dest = ev.getDestination();
var lastHops = dest["<<"](this._address.length());
if (lastHops.length() === 2) {
var command = lastHops.back().toString();
var numId = parseInt(lastHops.front().toString());
if ((command === "subscribe" || command === "get" || command === "ping") && numId === numId) {
var id = new Uint64(numId);
var child = this._createChildPage(id);
child["_h_" + command](ev);
} else {
this.trigger("serviceMessage", "ListPage model got a strange event: " + ev.toString(), 1);
}
} else {
this.trigger("serviceMessage", "ListPage model got a strange event: " + ev.toString(), 1);
}
},
"setParentReporter": function(pr) {
Page.fn.setParentReporter.call(this, pr);
this._pr.registerParent(this._list.getAddress(), this._list.reporterHandler);
this._pr.registerParent(this.getAddress(), this._reporterHandler);
this._list.subscribe();
},
"unsetParentReporter": function() {
this._pr.unregisterParent(this.getAddress());
this._pr.unregisterParent(this._list.getAddress());
Page.fn.unsetParentReporter.call(this);
}
});
module.exports = List;

198
magnus/pages/music.js Normal file
View file

@ -0,0 +1,198 @@
"use strict";
var Page = require("../lib/wModel/page");
var String = require("../lib/wModel/string");
var PanesList = require("../lib/wModel/panesList");
var Address = require("../lib/wType/address");
var Vocabulary = require("../lib/wType/vocabulary");
var Boolean = require("../lib/wType/boolean");
var Link = require("../lib/wModel/link");
var List = require("./list");
var Artist = require("./artist");
var Album = require("./album");
var Song = require("./song");
var PaneModel = require("../lib/wModel/proxy/pane");
var MusicPage = Page.inherit({
"className": "MusicPage",
"constructor": function(address, name) {
Page.fn.constructor.call(this, address, name);
this._dbConnected = false;
this._addresses = Object.create(null);
this._createAddresses();
var header = new String(this._address["+"](new Address(["header"])), "Music");
header.addProperty("fontFamily", "casualFont");
//var hvo = new Vocabulary();
this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop);
this._errMessage = new String(this._address["+"](new Address(["message"])), "Database is not connected");
this._errMessage.addProperty("fontFamily", "largeFont");
this._errMessage.addProperty("fontSize", "largeFontSize");
this.addItem(this._errMessage, 1, 0, 1, 1, Page.Aligment.CenterTop);
},
"destructor": function() {
if (this._dbConnected && this._hasParentReporter) {
this._destroyLists();
} else {
this.removeItem(this._errMessage);
}
this._errMessage.destructor();
for (var tag in this._addresses) {
var group = this._addresses[tag];
for (var name in group) {
group[name].destructor();
}
}
Page.fn.destructor.call(this);
},
"_createAddresses": function() {
var ra = new Address(["artists"]);
var ral = new Address(["albums"]);
var rs = new Address(["songs"]);
var artists = Object.create(null);
var albums = Object.create(null);
var songs = Object.create(null);
artists.remote = ra.clone();
artists.local = this._address["+"](ra);
albums.remote = ral.clone();
albums.local = this._address["+"](ral);
songs.remote = rs.clone();
songs.local = this._address["+"](rs);
this._addresses.artists = artists;
this._addresses.albums = albums;
this._addresses.songs = songs;
var PaneArtist = PaneModel.Artists;
if (!PaneArtist) {
PaneArtist = PaneModel.inherit({});
PaneModel.Artists = PaneArtist;
} else {
PaneArtist.pageAddress.destructor()
}
PaneArtist.pageAddress = artists.local.clone();
var PaneAlbum = PaneModel.Albums;
if (!PaneAlbum) {
PaneAlbum = PaneModel.inherit({});
PaneModel.Albums = PaneAlbum;
} else {
PaneAlbum.pageAddress.destructor()
}
PaneAlbum.pageAddress = albums.local.clone();
var PaneSongs = PaneModel.Songs;
if (!PaneSongs) {
PaneSongs = PaneModel.inherit({});
PaneModel.Songs = PaneSongs;
} else {
PaneSongs.pageAddress.destructor()
}
PaneSongs.pageAddress = songs.local.clone();
ra.destructor();
ral.destructor();
rs.destructor();
},
"_createLists": function(socket) {
this._artists = new List(
this._addresses.artists.local.clone(),
"Artists",
this._addresses.artists.remote.clone(),
socket,
Artist
);
this._artistsLink = new Link(this._address["+"](new Address(["artistsLink"])), "Artists", this._addresses.artists.local.clone());
this._artistsLink.label.addProperty("fontSize", "largeFontSize");
this._artistsLink.label.addProperty("fontFamily", "largeFont");
this._artistsLink.label.addProperty("color", "primaryFontColor");
this._artistsLink.addProperty("backgroundColor", "primaryColor");
this._albums = new List(
this._addresses.albums.local.clone(),
"Albums",
this._addresses.albums.remote.clone(),
socket,
Album
);
this._albumsLink = new Link(this._address["+"](new Address(["albumsLink"])), "Albums", this._addresses.albums.local.clone());
this._albumsLink.label.addProperty("fontSize", "largeFontSize");
this._albumsLink.label.addProperty("fontFamily", "largeFont");
this._albumsLink.label.addProperty("color", "primaryFontColor");
this._albumsLink.addProperty("backgroundColor", "primaryColor");
this._songs = new List(
this._addresses.songs.local.clone(),
"Songs",
this._addresses.songs.remote.clone(),
socket,
Song
);
this._songsLink = new Link(this._address["+"](new Address(["songsLink"])), "Songs", this._addresses.songs.local.clone());
this._songsLink.label.addProperty("fontSize", "largeFontSize");
this._songsLink.label.addProperty("fontFamily", "largeFont");
this._songsLink.label.addProperty("color", "primaryFontColor");
this._songsLink.addProperty("backgroundColor", "primaryColor");
this.addItem(this._artistsLink, 1, 0, 1, 1);
this.addItem(this._albumsLink, 2, 0, 1, 1);
this.addItem(this._songsLink, 3, 0, 1, 1);
this.addPage(this._artists);
this.addPage(this._albums);
this.addPage(this._songs);
},
"_destroyLists": function() {
this.removePage(this._artists);
this.removePage(this._albums);
this.removePage(this._songs);
this.removeItem(this._artistsLink);
this.removeItem(this._albumsLink);
this.removeItem(this._songsLink);
this._artists.destructor();
this._albums.destructor();
this._songs.destructor();
this._artistsLink.destructor();
this._albumsLink.destructor();
this._songsLink.destructor();
},
"showError": function() {
if (this._dbConnected) {
if (!this._hasParentReporter) {
throw new Error("Parent reporter is required in music page");
}
this._destroyLists()
this.addItem(this._errMessage, 1, 0, 1, 1, Page.Aligment.CenterTop);
this._dbConnected = false;
}
},
"showBandList": function(perturaboSocket) {
if (!this._hasParentReporter) {
throw new Error("Parent reporter is required in music page");
}
if (!this._dbConnected) {
this.removeItem(this._errMessage);
this._createLists(perturaboSocket);
this._dbConnected = true;
}
}
});
module.exports = MusicPage;

151
magnus/pages/song.js Normal file
View file

@ -0,0 +1,151 @@
"use strict";
var TempPage = require("./tempPage");
var String = require("../lib/wModel/string");
var Image = require("../lib/wModel/image");
var VCController = require("../lib/wController/vocabulary");
var Address = require("../lib/wType/address");
var Uint64 = require("../lib/wType/uint64");
var SongPage = TempPage.inherit({
"className": "SongPage",
"constructor": function(address, name, id, proxySocket) {
TempPage.fn.constructor.call(this, address, name);
this._remoteId = id;
this._proxySocket = proxySocket;
this._ctrls = Object.create(null);
var header = this._header = new String(this._address["+"](new Address(["header"])), "");
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 1, 1, 1, TempPage.Aligment.CenterTop);
var album = this._album = new String(this._address["+"](new Address(["album"])), "Album name");
album.addProperty("fontFamily", "casualFont");
this.addItem(album, 1, 1, 1, 1, TempPage.Aligment.CenterTop);
var artist = this._artist = new String(this._address["+"](new Address(["artist"])), "Artist name");
artist.addProperty("fontFamily", "casualFont");
this.addItem(artist, 2, 1, 1, 1, TempPage.Aligment.CenterTop);
var image = this._image = new Image(this._address["+"](new Address(["image"])), new Uint64(0));
this.addItem(image, 0, 0, 3, 1, TempPage.Aligment.CenterCenter);
},
"destructor": function() {
this._clearCtrls();
TempPage.fn.destructor.call(this);
},
"_clearCtrls": function() {
for (var key in this._ctrls) {
this._ctrls[key].destructor();
}
this._ctrls = Object.create(null);
},
"_onAlbumNewElement": function(key, el) {
switch(key) {
case "name":
this._album.set(el);
break;
case "image":
this._image.set(el.clone());
break;
}
},
"_onAlbumRemoveElement": function(key) {
switch(key) {
case "name":
this._album.set("unknown");
case "image":
this._image.set(new Uint64(0));
break;
}
},
"_onArtistNewElement": function(key, el) {
switch(key) {
case "name":
this._artist.set(el);
break;
}
},
"_onArtistRemoveElement": function(key) {
switch(key) {
case "name":
this._artist.set("unknown");
}
},
"_onSongNewElement": function(key, el) {
switch(key) {
case "name":
this._header.set(el);
break;
case "album":
if (this._ctrls.album) {
this.trigger("serviceMessage", "an album controller reinitializes in song page, not suppose to happen!", 1);
this._ctrls.album.destructor();
}
var aVC = new VCController(new Address(["albums", el.toString()]));
aVC.on("newElement", this._onAlbumNewElement, this);
aVC.on("removeElement", this._onAlbumRemoveElement, this);
this._ctrls.album = aVC;
aVC.register(this._dp, this._proxySocket);
aVC.subscribe();
break;
case "artist":
if (this._ctrls.artist) {
this.trigger("serviceMessage", "an artist controller reinitializes in song page, not suppose to happen!", 1);
this._ctrls.artist.destructor();
}
var arVC = new VCController(new Address(["artists", el.toString()]));
arVC.on("newElement", this._onArtistNewElement, this);
arVC.on("removeElement", this._onArtistRemoveElement, this);
this._ctrls.artist = arVC;
arVC.register(this._dp, this._proxySocket);
arVC.subscribe();
break;
}
},
"_onSongRemoveElement": function(key) {
switch(key) {
case "name":
this._header.set("");
break;
case "album":
this._album.set("");
this._ctrls.album.destructor();
delete this._ctrls.album;
case "artist":
this._artist.set("");
this._ctrls.artist.destructor();
delete this._ctrls.artist;
}
},
"register": function(dp, server) {
TempPage.fn.register.call(this, dp, server);
for (var key in this._ctrls) {
this._ctrls[key].register(dp, this._proxySocket);
}
},
"setParentReporter": function(pr) {
TempPage.fn.setParentReporter.call(this, pr);
var songVC = new VCController(new Address(["songs", this._remoteId.toString()]));
songVC.on("newElement", this._onSongNewElement, this);
songVC.on("removeElement", this._onSongRemoveElement, this);
this._ctrls.song = songVC;
songVC.register(this._dp, this._proxySocket);
songVC.subscribe();
},
"unsetParentReporter": function() {
this._clearCtrls();
TempPage.fn.unsetParentReporter.call(this);
}
});
module.exports = SongPage;

46
magnus/pages/tempPage.js Normal file
View file

@ -0,0 +1,46 @@
"use strict";
var Page = require("../lib/wModel/page");
var config = require("../config/config.json");
var TempPage = Page.inherit({
"className": "TempPage",
"constructor": function(address, name) {
Page.fn.constructor.call(this, address, name);
this._destructionTimeout = undefined;
},
"destructor": function() {
if (this._destructionTimeout) {
clearTimeout(this._destructionTimeout);
}
Page.fn.destructor.call(this);
},
"checkSubscribersAndDestroy": function() {
if (this._subscribersCount === 0 && this._destructionTimeout === undefined) {
this.trigger("serviceMessage", this._address.toString() + " has no more subscribers, destroying page");
this._destructionTimeout = setTimeout(this.trigger.bind(this, "destroyMe"), config.modelDestructionTimeout);
}
},
"_h_subscribe": function(ev) {
Page.fn._h_subscribe.call(this, ev);
if (this._destructionTimeout !== undefined) {
clearTimeout(this._destructionTimeout);
this._destructionTimeout = undefined;
}
},
"_h_unsubscribe": function(ev) {
Page.fn._h_unsubscribe.call(this, ev);
this.checkSubscribersAndDestroy();
},
"_onSocketDisconnected": function(ev, socket) {
Page.fn._onSocketDisconnected.call(this, ev, socket);
this.checkSubscribersAndDestroy();
}
});
module.exports = TempPage;

19
magnus/pages/test.js Normal file
View file

@ -0,0 +1,19 @@
"use strict";
var Page = require("../lib/wModel/page");
var String = require("../lib/wModel/string");
var Address = require("../lib/wType/address");
var TestPage = Page.inherit({
"className": "TestPage",
"constructor": function(address, name) {
Page.fn.constructor.call(this, address, name);
var header = new String(this._address["+"](new Address(["message"])), "This is a test page");
header.addProperty("fontFamily", "casualFont");
this.addItem(header, 0, 0, 1, 1, Page.Aligment.CenterTop);
}
});
module.exports = TestPage;

View file

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(test.js test.js)

64
magnus/test/test.js Normal file
View file

@ -0,0 +1,64 @@
"use strict";
var Class = require("../lib/utils/class");
var TUint64 = require("../lib/wTest/uint64");
var TAbstractMap = require("../lib/wTest/abstractmap");
var TAbstractList = require("../lib/wTest/abstractlist");
var TAbstractOrder = require("../lib/wTest/abstractorder");
var log = require("../lib/log")(module);
var Test = Class.inherit({
"className": "Test",
"constructor": function() {
Class.fn.constructor.call(this);
this._s = 0;
this._t = 0;
this._tests = [];
this.addTest(new TUint64());
this.addTest(new TAbstractList());
this.addTest(new TAbstractMap());
this.addTest(new TAbstractOrder());
},
"destructor": function() {
for (var i = 0; i < this._tests.length; ++i) {
this._tests[i].destructor();
}
Class.fn.destructor.call(this);
},
"addTest": function(test) {
test.on("start", this._onStart, this);
test.on("end", this._onEnd, this);
test.on("progress", this._onProgress, this);
test.on("fail", this._onFail, this);
this._tests.push(test);
},
"run": function() {
log.info("Starting tests");
for (var i = 0; i < this._tests.length; ++i) {
this._tests[i].run();
}
log.info("Testing complete. " + this._s + "/" + this._t);
},
"_onStart": function(name) {
log.info("Testing " + name);
},
"_onEnd": function(name, s, t) {
log.info("Finished " + name + ". " + s + "/" + t);
this._s += s;
this._t += t;
},
"_onProgress": function(name, current, total) {
},
"_onFail": function(name, current, error) {
log.warn("Test failed! Action " + current + ".");
log.warn("Error message:" + error.message);
log.warn("Error stack: \n" + error.stack);
}
});
module.exports = Test;

View file

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8.12)
configure_file(index.jade index.jade)

15
magnus/views/index.jade Normal file
View file

@ -0,0 +1,15 @@
//
Created by betrayer on 27.11.15.
doctype html
html(lang='en')
head
meta(charset='utf-8')
title RadioW
link(href='/css/main.css', rel='stylesheet')
script(data-main='/main' src='/lib/requirejs/require.js')
body
#serverMessage
= info
p I am