'use strict';
class Model {
constructor() {
this.words = new Map();
}
add_words(words) {
for (let word of words) {
this.words.set(word,1+(this.words.get(word) || 0));
}
}
get_most_common_pairs(how_many) {
let pairs = [...this.words];
pairs.sort((a,b) => { return b[1] - a[1] });
pairs.splice(how_many);
return pairs;
}
};
class View {
words_from_input(input) {
return input.split(/\s+/).filter(word => word.length > 0);
}
table_from_ranked_pairs(ranked_pairs) {
return ranked_pairs.map( pair => View.vsprintf('%-15s %3d',pair) ).join("\n");
}
};
View.vsprintf = require('sprintf-js').vsprintf;
class HTTPController {
constructor(model,view) {
this.model = model;
this.view = view;
}
on_request(req,res) {
if (req.method == 'GET') {
this.get_words(req,res)
}
else if (req.method == 'POST') {
this.post_words(req,res)
}
}
respond(res,text) {
res.setHeader('Content-type','text/plain');
res.statusCode = 200;
res.write(`${text}\n`,'',() => { res.end() });
}
get_words(req,res) {
const query = HTTPController.url_parse(req.url,true).query;
const how_many = query.n || 10;
const most_common_pairs = this.model.get_most_common_pairs(how_many);
const table = this.view.table_from_ranked_pairs(most_common_pairs);
this.respond(res,table);
}
post_words(req,res) {
let buffer = '';
req.on('data', (chunk) => {
buffer += chunk;
});
req.on('end', () => {
const words = this.view.words_from_input(buffer);
this.model.add_words(words);
this.respond(res,'ok');
})
}
}
HTTPController.url_parse = require('url').parse;
class LineController {
constructor(model,view) {
this.model = model;
this.view = view;
}
on_command(conn,command,args_string) {
if (command == 'get') {
this.get_words(conn,args_string);
}
else if (command == 'put') {
this.put_words(conn,args_string);
}
else {
this.reply(conn,"bad command, only 'get' and 'put'");
}
}
reply(conn,text) {
conn.write(`${text}\n`);
}
get_words(conn,args_string) {
const how_many = parseInt(args_string,10) || 10;
const most_common_pairs = this.model.get_most_common_pairs(how_many);
const table = this.view.table_from_ranked_pairs(most_common_pairs);
this.reply(conn,table);
}
put_words(conn,args_string) {
const words = this.view.words_from_input(args_string);
this.model.add_words(words);
this.reply(conn,'ok');
}
}
const net = require('net');
class TextServer extends net.Server {
constructor(controller) {
super( {}, (c) => {
c.setEncoding('utf-8');
let input='';
c.on('data', (buffer) => {
input += buffer;
let lines = input.split(/\r?\n/);
input = lines.pop();
for (const line of lines) {
const m = line.match(/^(\S+)(?:\s+(.+))?$/);
if (m) {
controller.on_command(
c,
m[1], m[2],
);
}
}
});
});
}
}
const model = new Model();
const view = new View();
const http = require('http');
const httpcontroller = new HTTPController(model,view);
const httpserver = http.createServer((req,res) => {
httpcontroller.on_request(req,res);
});
httpserver.listen(8080,'localhost');
const linecontroller = new LineController(model,view);
const textserver = new TextServer(linecontroller);
textserver.listen(2020,'localhost');