-
Notifications
You must be signed in to change notification settings - Fork 0
/
shortener.js
121 lines (98 loc) · 3.68 KB
/
shortener.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* shortener.js is a human-readable URL shortener, perfect for those times when
* you need to share long URLs with other humans.
*
* Written by Aaron Vontell, Founder of Vontech Software, LLC
*/
// Module dependencies
const fs = require('fs'); // Used for opening the word file
const lineReader = require('readline'); // Used for buffering the file line by line
// Predefined constants
const baseDomain = "https://mywebsite.com/"
const wordFilePath = "resources/google-10000-english-usa-no-swears.txt";
const minWordLength = 3
const maxWordLength = 6
// Cached global variables
var words = []
var urlDictionary = {}
/**
* Loads a list of words from the file at `wordFilePath`, which should contain
* a list of newline-delimited words. Uses lineReader to do this in a buffered
* and asynchronous manner.
* callback - A function that gets called when the file is done being read
* (callback should not take any parameters)
*/
function loadValidWords(callback) {
// If we already loaded the words, just return the already-loaded words!
if (words.length > 0) {
return words;
}
// Otherwise, startup the buffered reader
var instance = lineReader.createInterface({
input: fs.createReadStream(wordFilePath)
});
// If a line is encountered, add it to our list if it satisfies the length
// constraints
instance.on('line', function (line) {
var wordLength = line.length;
if (wordLength >= minWordLength && wordLength <= maxWordLength)
words.push(line);
});
// Once finished, call the callback
instance.on('close', function (line) {
callback();
});
}
/**
* Returns a shortened version of the given `url`, which is saved for later
* retrieval.
* url - The url to shorten
*/
function shortenURL(url) {
// Grab a random word, removing it from the list
// Note that we are splicing the original word list in order to
// efficiently resize the existing array
var randInt = getRandomInt(0, words.length - 1);
var randWord = words.splice(randInt, 1)[0];
// Save the random word --> url mapping
urlDictionary[randWord] = url;
// Return the shortened version of the URL
return baseDomain + randWord;
}
/**
* Returns the saved URL given the shortened URL (generated by this program)
* shortenedURL - A shortened URL generated by this program instance
*/
function getURLFromShortened(shortenedURL) {
return urlDictionary[shortenedURL.replace(baseDomain, "")];
}
/**
* Deletes the shortened URL record associated with the given shortenedURL,
* returning the short URL word used back to the word pool.
* shortenedURL - A shortened URL generated by this program instance
*/
function removeShortenedURL(shortenedURL) {
var word = shortenedURL.replace(baseDomain, "");
delete urlDictionary[word];
words.push(word);
}
/**
* Returns a random integer between min (inclusive) and max (inclusive)
* Using Math.round() will give you a non-uniform distribution!
* Obtained from https://stackoverflow.com/questions/1527803
* /generating-random-whole-numbers-in-javascript-in-a-specific-range
*/
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function startServer() {
loadValidWords(function() {
console.log("Available words: " + words.length);
var newURL = shortenURL("https://medium.com/365-days-of-coding");
console.log("New URL: " + newURL);
var oldURL = getURLFromShortened(newURL);
console.log("Old URL: " + oldURL);
removeShortenedURL(newURL);
});
}
startServer()