Initial commit.
This commit is contained in:
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"program": "${workspaceFolder}/index.js"
|
||||
}
|
||||
]
|
||||
}
|
29
geminiroot/localhost/index.gml
Normal file
29
geminiroot/localhost/index.gml
Normal file
@ -0,0 +1,29 @@
|
||||
# Uplink Gopher Server
|
||||
|
||||
A story of an old gopher server
|
||||
|
||||
A long time ago I wrote a little gopher client in C#. It was a fun excersize as I was learning to program. To test it I also wrote a little server to go along with it. Years passed and my gopher client can't handle a big part of the net that switched to IPv6. Oh well. The server works as intended, but the old 3.5 .net framework is outdated. I would need to recompile it but I cannot make the new mono compilers work on Solaris (the old one works fine). So I fel t a little stuck with the old server and old framework. And a half working client.
|
||||
|
||||
Then one day I found gemini protocol and several projects around it that also support gopher protocol. I especially liked Lagrange client that can handle gemini and gopher. I began research and experimentation. I like how it renders menues, how it displays text. It makes this old prtocol shine with the beautiful typografy. It really is my new favourite way to look at gopher.
|
||||
|
||||
=> gemini://gemini.circumlunar.space/docs/ Gemini protocol
|
||||
=> gemini://skyjake.fi/lagrange/ Lagrange
|
||||
|
||||
Gemini (and Lagrange in particular) took several ideas from gopher and some from the www and created gemini. Even better - these new paradigms were then applied to gopher aswell.
|
||||
|
||||
Let me elaborate a little on this paradigm shift.
|
||||
|
||||
Gopher is a protocol that serves two kinds of content - menus and files (ok, there are also several others like images, links to telnet servers, search items and so on). Menus are - as far as gopher is concerned - just that - menus. Items can be seen as files, just like in ftp. There is even gopher file system driver - you can mount gopher server as filesystem under linux. Lagrange displays menus as a form of websites.
|
||||
|
||||
When I was creating my gopher client and server, now about ten years ago, I never tought about that. My client takes the menu content and renders it in a full window listbox element. I tought about this listbox as being a "page" ... but man, Lagrange really took it to the next level.
|
||||
|
||||
And this kind of thinking opens up new ideas - that got implemented into gemini servers. Gemtext files - gemini markup language. Markup for menus that are really pages. This could be applied to gopher aswell. Others probably already did it ... I had to try.
|
||||
|
||||
So I created a small gopher server in NodeJS. 99 lines of code at the moment. It takes gemtext file and transorms it - line by line - into gopher menu and then sends it over to the client. Works nicely.
|
||||
|
||||
99 lines of code is not a lot. I did not bother implementing folder browsing. Folder browsing is so ... 80's when it comes to gopher. Or maybe 2010. Gemini influence is ... at least for me - a new boost in interest for gopher.
|
||||
|
||||
But my previous server was capable of properly handling Gopher+ requests. The chalange is to do the same in NodeJS. That might prove to be a chalange indeed as the paradigm shift never took Gopher+ into account. Will try it, lets see hot it works.
|
||||
|
||||
And that is not all, by any mean. As gemtext supports some formating, similar to what is supported in markdown, you can mark titles, lists and so on. Markup is a really small subset of markdown, but nevertheless usefull. And that very same markup can be used also in gopher. And Lagrange will happily format the text accordingly. Wow.
|
||||
|
40
geminiroot/localhost/index1.gml
Normal file
40
geminiroot/localhost/index1.gml
Normal file
@ -0,0 +1,40 @@
|
||||
# Getting Started
|
||||
|
||||
New to Gemini? Here are a few bookmarks to get you started.
|
||||
|
||||
=> gemini://geminiquickst.art/ Gemini Quickstart: installing a client, finding and publishing content
|
||||
|
||||
## Project Gemini
|
||||
|
||||
=> gemini://gemini.circumlunar.space/ Project Gemini
|
||||
=> gemini://gemini.circumlunar.space/capcom/ CAPCOM Geminispace Aggregator
|
||||
=> gemini://gemini.circumlunar.space/software/ List of Gemini servers, clients, and other software
|
||||
|
||||
## Search & Directories
|
||||
|
||||
=> gemini://geminispace.info/ geminispace.info - Gemini Search Engine
|
||||
The largest Gemini search engine. Also displays statistics about Geminispace.
|
||||
|
||||
=> gemini://medusae.space/ medusae.space Gemini Directory
|
||||
A curated collection of categorized capsules.
|
||||
|
||||
=> gemini://review.treeblue.space/ The Treeblue Review
|
||||
Curated feeds and links.
|
||||
|
||||
## Gemlogs
|
||||
|
||||
=> gemini://warmedal.se/~antenna/ Antenna
|
||||
Aggregator of feed entries from around Geminispace.
|
||||
|
||||
## Forums/Social
|
||||
|
||||
=> gemini://station.martinrue.com Station
|
||||
Microblogging with likes and replies.
|
||||
|
||||
=> gemini://geddit.glv.one/ Geddit
|
||||
Post links and comment anonymously.
|
||||
|
||||
## Lagrange
|
||||
|
||||
=> about:help Lagrange User Manual
|
||||
|
40
geminiroot/localhost/podmapa/index.gml
Normal file
40
geminiroot/localhost/podmapa/index.gml
Normal file
@ -0,0 +1,40 @@
|
||||
# Getting Started
|
||||
|
||||
New to Gemini? Here are a few bookmarks to get you started.
|
||||
|
||||
=> gemini://geminiquickst.art/ Gemini Quickstart: installing a client, finding and publishing content
|
||||
|
||||
## Project Gemini
|
||||
|
||||
=> gemini://gemini.circumlunar.space/ Project Gemini
|
||||
=> gemini://gemini.circumlunar.space/capcom/ CAPCOM Geminispace Aggregator
|
||||
=> gemini://gemini.circumlunar.space/software/ List of Gemini servers, clients, and other software
|
||||
|
||||
## Search & Directories
|
||||
|
||||
=> gemini://geminispace.info/ geminispace.info - Gemini Search Engine
|
||||
The largest Gemini search engine. Also displays statistics about Geminispace.
|
||||
|
||||
=> gemini://medusae.space/ medusae.space Gemini Directory
|
||||
A curated collection of categorized capsules.
|
||||
|
||||
=> gemini://review.treeblue.space/ The Treeblue Review
|
||||
Curated feeds and links.
|
||||
|
||||
## Gemlogs
|
||||
|
||||
=> gemini://warmedal.se/~antenna/ Antenna
|
||||
Aggregator of feed entries from around Geminispace.
|
||||
|
||||
## Forums/Social
|
||||
|
||||
=> gemini://station.martinrue.com Station
|
||||
Microblogging with likes and replies.
|
||||
|
||||
=> gemini://geddit.glv.one/ Geddit
|
||||
Post links and comment anonymously.
|
||||
|
||||
## Lagrange
|
||||
|
||||
=> about:help Lagrange User Manual
|
||||
|
130
geminiroot/localhost/test.gml
Normal file
130
geminiroot/localhost/test.gml
Normal file
@ -0,0 +1,130 @@
|
||||
# CAPCOM Geminispace aggregator
|
||||
|
||||
CAPCOM is an aggregator for Atom feeds of Gemini content. It was inspired by:
|
||||
=> gopher://i-logout.cz:70/1/bongusta/ The Bongusta aggregator for Gopherspace
|
||||
|
||||
Each month, CAPCOM randomly selects 100 distinct URLs from its list of known feeds, and includes their content in its output. This makes it a nice way to discover new content in Geminispace. If you're enjoying content from one feed, you should subscribe to it yourself in some way, because that feed is not guaranteed to be one of the 100 feeds chosen next month!
|
||||
=> submit Submit your Atom feed's URL for inclusion in CAPCOM's list
|
||||
=> feeds.txt See this month's active feeds
|
||||
|
||||
If you want to maintain your *own* set of aggregated feeds, either for public consumption or your own private use, you can:
|
||||
=> https://tildegit.org/solderpunk/CAPCOM Download the CAPCOM software
|
||||
|
||||
To find feeds to add to your own CAPCOM instance, you can:
|
||||
=> submitted-feeds.txt See all feed URLs known by this CAPCOM instance
|
||||
=> gemini://gus.guru/known-feeds See all feed URLs known to the GUS search engine
|
||||
|
||||
Aggregating 100 Atom feeds from Geminispace.
|
||||
|
||||
## 2021-12-04
|
||||
|
||||
=> gemini://gemini.marmaladefoo.com/blog/3-Dec-2021_Making_yncke.gmi Luke's Gemlog - Making Yncke
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-04-how-much-is-published-on-gemlogs.gmi ew0k is a Teddybear - How Much is Published on Gemlogs?
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-04-advent-of-bloggers-2021-dec-4th.gmi ew0k is a Teddybear - Advent of Bloggers 2021, Dec 4th
|
||||
|
||||
## 2021-12-03
|
||||
|
||||
=> gemini://compudanzas.net/qiudanz_devlog.gmi compudanzas - qiudanz technique in the slomoco fall gathering
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-03-advent-of-bloggers-2021-dec-3rd.gmi ew0k is a Teddybear - Advent of Bloggers 2021, Dec 3rd
|
||||
=> gemini://si3t.ch/log/2021-12-03-gmi2html-details.gmi log de prx - gmi2html.awk : support des médias
|
||||
|
||||
## 2021-12-02
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-02-hollywood-world-rescue.gmi ew0k is a Teddybear - Hollywood World Rescue
|
||||
=> gemini://si3t.ch/log/2021-12-02-gmi2htmlawk.gmi log de prx - gmi2html.awk
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-02-advent-of-bloggers-2021-dec-2nd.gmi ew0k is a Teddybear - Advent of Bloggers 2021, Dec 2nd
|
||||
=> gemini://gemini.cyberbot.space/gemlog/2021-12-02-breadgamesmusic.gmi kelbot's gemlog - Bread, smolZINE, Videogames and Records
|
||||
|
||||
## 2021-12-01
|
||||
|
||||
=> gemini://si3t.ch/log/2021-12-01-gemcol.gmi log de prx - Colorer un fichier écrit en gemtext
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-12-01-advent-of-bloggers-2021-dec-1st.gmi ew0k is a Teddybear - Advent of Bloggers 2021, Dec 1st
|
||||
=> gemini://compudanzas.net/advent_of_code_2021.gmi compudanzas - started advent of code 2021 using awk
|
||||
=> gemini://gemini.circumlunar.space/~adiabatic/scrawlspace/ Halfway to Mars - You might want to check all CAPCOM posts at the start of a new month, not just the new ones.
|
||||
|
||||
## 2021-11-30
|
||||
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-30_The_difference_between_archiving_and_record_keeping Alex Schroeder - 2021-11-30 The difference between archiving and record keeping
|
||||
=> gemini://moddedbear.xyz/logs/2021-11-30-november-is-gone.gmi moddedBear's log - November Is Gone: Thanksgiving, Burnout, and More
|
||||
=> gemini://gemini.circumlunar.space/~adiabatic/scrawlspace/ Halfway to Mars - I consider when to start trimming my feeds and briefly take a trip down memory lane.
|
||||
=> gemini://jsreed5.org/log/2021/202111/20211130-scope.gmi Rob's Gemini Capsule - Scope
|
||||
|
||||
## 2021-11-29
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-29-time-energy-motivation-pick-two.gmi ew0k is a Teddybear - Time, Energy, Motivation: Pick Two
|
||||
=> gemini://si3t.ch/log/2021-11-29-emoji-fzf-vi-snippets.gmi log de prx - Sélection/insertion d'emojis (ou autre) avec vi et fzf
|
||||
=> gemini://jsreed5.org/log/2021/202111/20211129-2021-week-46-47-thoughts-and-catch-up.gmi Rob's Gemini Capsule - 2021 Week 46/47: Thoughts and Catch-up
|
||||
|
||||
## 2021-11-28
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-28-killing-zombie-children-and-other-it-terms.gmi ew0k is a Teddybear - "Killing Zombie Children" and Other IT Terms
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-28-some-quick-antenna-stats.gmi ew0k is a Teddybear - Some Quick Antenna Stats
|
||||
=> gemini://jsreed5.org/log/2021/202111/20211128-the-movie-theater.gmi Rob's Gemini Capsule - The Movie Theater
|
||||
|
||||
## 2021-11-27
|
||||
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-27_Emacs_as_a_way_of_life Alex Schroeder - 2021-11-27 Emacs as a way of life
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-27-damn-small-software.gmi ew0k is a Teddybear - Damn Small Software
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-27-running-in-the-cold.gmi ew0k is a Teddybear - Running in the Cold
|
||||
|
||||
## 2021-11-26
|
||||
|
||||
=> gemini://compudanzas.net/qiudanz_devlog.gmi compudanzas - fourth qiudanz technique mini workshop
|
||||
=> gemini://shit.cx/other/2021-11-26-making-a-leather-belt/ shit.cx - Making a Leather Belt
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-26_Random_tables%2C_again Alex Schroeder - 2021-11-26 Random tables, again
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-26_Why_I_hate_bots Alex Schroeder - 2021-11-26 Why I hate bots
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-26_Colours_in_our_texts Alex Schroeder - 2021-11-26 Colours in our texts
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-26_Unhappy_thoughts_when_reading_social_media Alex Schroeder - 2021-11-26 Unhappy thoughts when reading social media
|
||||
=> gemini://jsreed5.org/log/2021/202111/20211126-thanksgiving-2021.gmi Rob's Gemini Capsule - Thanksgiving 2021
|
||||
=> gemini://gemini.circumlunar.space/~adiabatic/scrawlspace/ Halfway to Mars - I explain how and why I do things differently when I’m writing in gemtext as opposed to Markdown.
|
||||
=> gemini://gemini.circumlunar.space/~adiabatic/unfiled/parthenon/ Halfway to Mars - I add Howard Roark’s critique of the Parthenon so I don’t have to look at it on an unstyled web page with no dark mode, em dashes, or curly quotes.
|
||||
=> gemini://gemini.circumlunar.space/~adiabatic/scrawlspace/ Halfway to Mars - I ponder all the different speeds I can charge my laptop at.
|
||||
=> gemini://sbg.one/gemfeed/2021-11-26-audio-update.gmi SandboxGeneral - Audio Update Part 2
|
||||
|
||||
## 2021-11-25
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-25-i-once-transitioned-a-friend-from-windows-to-ubuntu.gmi ew0k is a Teddybear - I Once Transitioned a Friend From Windows to Ubuntu
|
||||
=> gemini://rwv.io/2021-11-25-nix-on-guix.gmi RWV.io - Nix on Guix notes
|
||||
=> gemini://gemini.cyberbot.space/gemlog/2021-11-25-pdatuiriffing.gmi kelbot's gemlog - Some More Riffing on PDAs and TUIs
|
||||
|
||||
## 2021-11-24
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-24-i-want-my-next-phone-to-have-a-headphone-jack.gmi ew0k is a Teddybear - I Want My Next Phone to Have a Headphone Jack
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-24-crashing-things-in-space-for-science.gmi ew0k is a Teddybear - Crashing Things in Space For Science!
|
||||
=> gemini://compudanzas.net/qiudanz_devlog.gmi compudanzas - third qiudanz technique mini workshop
|
||||
=> gemini://drewdevault.com/2021/11/24/A-philosophy-for-instant-messaging.gmi Drew DeVault's Geminispace blog - My philosophy for productive instant messaging
|
||||
=> gemini://capsule.usebox.net/gemlog/20211124-not-feeling-it.gmi Juan's Personal Gemlog - Not feeling it
|
||||
|
||||
## 2021-11-23
|
||||
|
||||
=> gemini://shit.cx/other/2021-11-23-hat-band/ shit.cx - Hat Band
|
||||
=> gemini://moddedbear.xyz/logs/2021-11-23-covers-better-than-the-originals.gmi moddedBear's log - Covers Better Than the Originals
|
||||
=> gemini://si3t.ch/log/2021-11-23-differents-aspects-site.gmi log de prx - Les différents aspects de ce site
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-23_Episode_39 Alex Schroeder - 2021-11-23 Episode 39
|
||||
|
||||
## 2021-11-22
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-22-non-sugary-desserts.gmi ew0k is a Teddybear - Non-sugary Desserts?
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-22-re-do-you-write-about-non-technical-stuff-on-your-gemlog.gmi ew0k is a Teddybear - Re: Do you write about non-technical stuff on your gemlog?
|
||||
=> gemini://gemini.cyberbot.space/gemlog/2021-11-22-pranks.gmi kelbot's gemlog - Computer Pranks and Fun
|
||||
|
||||
## 2021-11-21
|
||||
|
||||
=> gemini://compudanzas.net/intro_to_uxn_programming.gmi compudanzas - taught and enjoyed our intro to uxn programming online workshop via babycastles academy!
|
||||
=> gemini://g.moi.lc/minilog.gmi Une capsule Gemini francophone - Minilog, ou GLOG (Gemini Log)
|
||||
=> gemini://jsreed5.org/log/2021/202111/20211121-last-nights-drinks.gmi Rob's Gemini Capsule - Last Night's Drinks
|
||||
=> gemini://gemini.cyberbot.space/gemlog/2021-11-21-tuis.gmi kelbot's gemlog - RE: Lightweight GUIs, TUIs
|
||||
|
||||
## 2021-11-20
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-20-re-re-lightweight-simple-and-cross-platform-gui-programming.gmi ew0k is a Teddybear - Re: Re: Lightweight, Simple, and Cross-Platform GUI Programming?
|
||||
=> gemini://si3t.ch/log/2021-11-20-livres-favoris.gmi log de prx - Les livres que j'ai aimé
|
||||
=> gemini://alexschroeder.ch:1965/page/2021-11-20_Climate_Catastrophe_in_1990 Alex Schroeder - 2021-11-20 Climate Catastrophe in 1990
|
||||
=> gemini://kota.nz/notes/warm_days/ Kota's blog - Warm Days
|
||||
=> gemini://drewdevault.com/2021/11/20/Dark-forest.gmi Drew DeVault's Geminispace blog - An alternative to the Dark Forest hypothesis
|
||||
|
||||
## 2021-11-19
|
||||
|
||||
=> gemini://warmedal.se/~bjorn/posts/2021-11-19-lightweight-simple-and-cross-platform-gui-programming.gmi ew0k is a Teddybear - Lightweight, Simple, and Cross-Platform GUI Programming?
|
||||
=> gemini://compudanzas.net/qiudanz_devlog.gmi compudanzas - first check-in meeting with slomoco fall microresidents
|
||||
|
23
index.js
Normal file
23
index.js
Normal file
@ -0,0 +1,23 @@
|
||||
var uplinkGemini = require('./uplink-gemini');
|
||||
|
||||
var index = require('./routes/index');
|
||||
var user_add = require('./routes/user').user_add;
|
||||
var user_del = require('./routes/user').user_del;
|
||||
var user = require('./routes/user').user;
|
||||
var info = require('./routes/info');
|
||||
var input = require('./routes/input');
|
||||
var upload = require('./routes/upload');
|
||||
|
||||
const app = new uplinkGemini.App();
|
||||
const gemini = new uplinkGemini.Gemini();
|
||||
|
||||
gemini.router.use('/user/add/:first/:last', user_add);
|
||||
gemini.router.use('/user/del/:first/:last', user_del);
|
||||
gemini.router.use('/info/:first', info);
|
||||
gemini.router.use('/user', user);
|
||||
gemini.router.use('/', index);
|
||||
gemini.router.use('/input/', input);
|
||||
gemini.router.use('/upload/', upload);
|
||||
|
||||
gemini.listen();
|
||||
|
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "gemini",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
15
routes/index.js
Normal file
15
routes/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
/* GET home page. */
|
||||
function index(request, response) {
|
||||
response.send(
|
||||
`20 text/gemini\r\n
|
||||
# Pozdravljeni na Gemini strežniku :)
|
||||
Pozdravljen, ${request.clientCert.subject.CN}. Dobrodošel domov, poveljnik.
|
||||
=> /user/add/Simona/Kravcar Dodaj uporabnika Simona Kravcar
|
||||
=> /user/del/Simona/Kravcar Izbriši uporabnika Simona Kravcar
|
||||
=> /user Seznam uporabnikov
|
||||
=> /info/Simona Informacije o uporabniku Simona
|
||||
=> /input/ Testiranje vnosa
|
||||
=> titan://localhost/upload/`);
|
||||
}
|
||||
|
||||
module.exports = index;
|
7
routes/info.js
Normal file
7
routes/info.js
Normal file
@ -0,0 +1,7 @@
|
||||
/* GET home page. */
|
||||
function info(req, res) {
|
||||
var response = "# Info o uporabniku\r\nTo je uporabnik " + req.params.first + '.\r\n=> / Indeks\r\n';
|
||||
res.send('20 text/gemini\r\n' + response + '\r\n');
|
||||
}
|
||||
|
||||
module.exports = info;
|
10
routes/input.js
Normal file
10
routes/input.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* GET home page. */
|
||||
function input(req, res) {
|
||||
if(req.search === '') {
|
||||
res.send('10 Your name:\r\n');
|
||||
} else {
|
||||
res.send(`20 text/gemini\r\n# Rezultati iskanja:\r\nIskali ste: ${req.search}\r\n`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = input;
|
10
routes/upload.js
Normal file
10
routes/upload.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* GET home page. */
|
||||
function upload(req, res) {
|
||||
if(req.protocol == 'titan:') {
|
||||
res.send(`30 gemini://${req.hostname}/upload/\r\n`);
|
||||
} else {
|
||||
res.send('20 text/gemini\r\n#Upload area ...\r\n');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = upload;
|
20
routes/user.js
Normal file
20
routes/user.js
Normal file
@ -0,0 +1,20 @@
|
||||
/* GET home page. */
|
||||
function user(req, res) {
|
||||
var response = "# Uporabnik\r\nTo je stran z uporabniki " + JSON.stringify(req);
|
||||
res.send('20 text/gemini\r\n' + response + '\r\n');
|
||||
}
|
||||
|
||||
function user_add(req, res) {
|
||||
var response = "# Nov uporabnik\r\nUstvarili smo novega uporabnika z imenom " + req.params.first + " " + req.params.last + '\r\n' +
|
||||
'=> /info/' + req.params.first + ' Podatki uporabnika ' + req.params.first + '\r\n';
|
||||
res.send('20 text/gemini\r\n' + response + '\r\n');
|
||||
}
|
||||
|
||||
function user_del(req, res) {
|
||||
var response = "# Brisanje uporabnika\r\nIzbrisan je uporabnik z imenom " + JSON.stringify(req);
|
||||
res.send('20 text/gemini\r\n' + response + '\r\n');
|
||||
}
|
||||
|
||||
module.exports.user = user;
|
||||
module.exports.user_add = user_add;
|
||||
module.exports.user_del = user_del;
|
7
uplink-gemini/index.js
Normal file
7
uplink-gemini/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Gemini Library
|
||||
*/
|
||||
|
||||
//'use strict';
|
||||
|
||||
module.exports = require('./lib/uplink-gemini');
|
90
uplink-gemini/lib/request.js
Normal file
90
uplink-gemini/lib/request.js
Normal file
@ -0,0 +1,90 @@
|
||||
// Uplink Gemini Server
|
||||
// Request Class
|
||||
|
||||
const url = require('url').URL;
|
||||
|
||||
module.exports = class Request {
|
||||
constructor() {
|
||||
this.rawRequest = '';
|
||||
this.protocol = 'gemini:';
|
||||
this.hostname = 'localhost';
|
||||
this.port = 1965;
|
||||
this.path = '/';
|
||||
this.search = '';
|
||||
this.clientCert = undefined;
|
||||
this.content = '';
|
||||
this.contentMime = '';
|
||||
this.clientIP = '';
|
||||
this.clientPort = '';
|
||||
this.clientFamily = '';
|
||||
}
|
||||
|
||||
parseRequest() {
|
||||
var tempRequest = this.rawRequest.toString();
|
||||
var tempUrl = tempRequest.substring(0, tempRequest.indexOf('\r\n'));
|
||||
if(tempUrl.startsWith('titan:')) {
|
||||
var urlComponents = tempUrl.split(';');
|
||||
tempUrl = urlComponents[0];
|
||||
for(var i = 1; i < urlComponents.length; i++) {
|
||||
if(urlComponents[i].startsWith('mime=')) {
|
||||
this.contentMime = urlComponents[i].replace('mime=', '');
|
||||
} else if (urlComponents[i].startsWith('size=')) {
|
||||
this.contentSize = urlComponents[i].replace('size=', '');
|
||||
} else if (urlComponents[i].startsWith('token=')) {
|
||||
this.contentToken = urlComponents[i].replace('token=', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
//var lines = tempUrl.substring(0,)
|
||||
tempUrl = tempUrl.trim();
|
||||
try {
|
||||
const geminiUrl = new url(tempUrl);
|
||||
this.protocol = geminiUrl.protocol;
|
||||
this.hostname = geminiUrl.hostname;
|
||||
if (geminiUrl.port) this.port = geminiUrl.port;
|
||||
this.path = geminiUrl.pathname;
|
||||
this.search = geminiUrl.search.substring(1); //remove '?' from string
|
||||
if(this.protocol === 'titan:') {
|
||||
this.content = this.rawRequest.slice(this.rawRequest.indexOf('\r\n') + 3);
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
setRawRequest(rawRequest) {
|
||||
this.rawRequest = rawRequest;
|
||||
}
|
||||
|
||||
getRawRequest() {
|
||||
return this.rawRequest;
|
||||
}
|
||||
|
||||
setClientCert(clientCert) {
|
||||
this.clientCert = clientCert;
|
||||
}
|
||||
|
||||
setClientIP(ipAddress) {
|
||||
this.clientIP = ipAddress;
|
||||
}
|
||||
|
||||
getClientIP() {
|
||||
return this.clientIP;
|
||||
}
|
||||
|
||||
setClientPort(port) {
|
||||
this.clientPort = port;
|
||||
}
|
||||
|
||||
getClientPort() {
|
||||
return this.clientPort;
|
||||
}
|
||||
|
||||
setClientFamily(family) {
|
||||
this.clientFamily = family;
|
||||
}
|
||||
|
||||
getClientFamily() {
|
||||
return this.clientFamily;
|
||||
}
|
||||
};
|
31
uplink-gemini/lib/response.js
Normal file
31
uplink-gemini/lib/response.js
Normal file
@ -0,0 +1,31 @@
|
||||
// Uplink Gemini Server
|
||||
// Response Class
|
||||
|
||||
module.exports = class Response {
|
||||
constructor() {
|
||||
this.socket = undefined;
|
||||
this.status = undefined;
|
||||
}
|
||||
|
||||
setSocket(socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
getSocket() {
|
||||
return this.socket;
|
||||
}
|
||||
|
||||
send(data) {
|
||||
this.status = 20;
|
||||
this.socket.write(data);
|
||||
}
|
||||
|
||||
error(code) {
|
||||
this.status = code;
|
||||
this.socket.write(`${code} Error\r\n`);
|
||||
}
|
||||
|
||||
end() {
|
||||
this.socket.end();
|
||||
}
|
||||
};
|
109
uplink-gemini/lib/router.js
Normal file
109
uplink-gemini/lib/router.js
Normal file
@ -0,0 +1,109 @@
|
||||
// Uplink Gemini Server
|
||||
// Router Class
|
||||
|
||||
function selectRoute(path, routes) {
|
||||
result = -1;
|
||||
console.log(path);
|
||||
var mPathComponents = path.split('/');
|
||||
routes.forEach((item, index) => {
|
||||
console.log(item);
|
||||
var mitem = item.split('/');
|
||||
if((mitem.length == mPathComponents.length)) {
|
||||
if((item.indexOf(':') > 0) && (path.endsWith('/') == false)) {
|
||||
console.log('we need parameters');
|
||||
var mmitem = item.substring(item.indexOf(':'));
|
||||
var mmpath = path.substring(item.indexOf(':'));
|
||||
var mmitemList = mmitem.split('/');
|
||||
var mmpathList = mmpath.split('/');
|
||||
if(mmitemList.length == mmpathList.length) {
|
||||
console.log('winner is here');
|
||||
if(result == -1) result = index;
|
||||
}
|
||||
} else {
|
||||
console.log('we do not need parameters');
|
||||
if(item == path) {
|
||||
console.log('winnere here');
|
||||
if(result == -1) result = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = class Router {
|
||||
constructor() {
|
||||
this.routes = [];
|
||||
this.handlers = [];
|
||||
}
|
||||
|
||||
use(route, handler) {
|
||||
this.routes[this.routes.length] = route;
|
||||
this.handlers[this.handlers.length] = handler;
|
||||
this.request = undefined;
|
||||
this.response = undefined;
|
||||
}
|
||||
|
||||
set(path, request, response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
|
||||
/////////////////////////////////////
|
||||
console.log(selectRoute(path, this.routes));
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
var pathComponents = path.split('/');
|
||||
for (var i = 0; i < pathComponents.length; i++) {
|
||||
pathComponents[i] = '/' + pathComponents[i];
|
||||
}
|
||||
|
||||
var routes = this.routes;
|
||||
|
||||
var paths = [];
|
||||
var params = [];
|
||||
|
||||
var mindex = selectRoute(path, this.routes);
|
||||
|
||||
if(mindex == -1) {
|
||||
this.response.error(51);
|
||||
return;
|
||||
}
|
||||
|
||||
var routeComponents = routes[mindex].split('/');
|
||||
paths = [];
|
||||
params = [];
|
||||
|
||||
if (routeComponents.length == pathComponents.length) {
|
||||
for (var k = 0; k < routeComponents.length; k++) {
|
||||
routeComponents[k] = '/' + routeComponents[k];
|
||||
if (routeComponents[k].startsWith('/:')) {
|
||||
params.push(routeComponents[k]);
|
||||
} else {
|
||||
paths.push(routeComponents[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var finalParams = pathComponents.slice(paths.length);
|
||||
for (var l = 0; l < finalParams.length; l++) {
|
||||
finalParams[l] = finalParams[l].substring(1);
|
||||
}
|
||||
var myParams = {};
|
||||
for (var m = 0; m < params.length; m++) {
|
||||
eval('myParams.' + params[m].substring(2) + ' = "' + JSON.stringify(finalParams[m]).slice(1, -1) + '"');
|
||||
}
|
||||
|
||||
this.request.params = myParams;
|
||||
var mm = typeof this.handlers[mindex];
|
||||
if (mm !== 'undefined') {
|
||||
this.handlers[mindex](this.request, this.response);
|
||||
return;
|
||||
} else {
|
||||
this.response.error(51);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
133
uplink-gemini/lib/uplink-gemini.js
Normal file
133
uplink-gemini/lib/uplink-gemini.js
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Gemini Library
|
||||
*/
|
||||
|
||||
//'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const constants = require('constants');
|
||||
const tls = require('tls');
|
||||
const url = require('url').URL;
|
||||
|
||||
const Router = require('./router');
|
||||
const Request = require('./request');
|
||||
const Response = require('./response');
|
||||
const { time } = require('console');
|
||||
|
||||
const router = new Router();
|
||||
const req = new Request();
|
||||
const res = new Response();
|
||||
|
||||
|
||||
module.exports.App = class App {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
display() {
|
||||
console.log("my Name is " + this.name);
|
||||
}
|
||||
|
||||
valid(startdate, enddate) {
|
||||
var startdate_ = Date.parse(startdate);
|
||||
var enddate_ = Date.parse(enddate);
|
||||
var today_ = Date.now();
|
||||
|
||||
if (today_ >= startdate_ && today_ <= enddate_) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fileExist(path) {
|
||||
return fs.existsSync(settings.root + path);
|
||||
}
|
||||
|
||||
isDirectory(path) {
|
||||
return fs.statSync(settings.root + path).isDirectory();
|
||||
}
|
||||
|
||||
getPage(path, next) {
|
||||
var index;
|
||||
fs.readFile(this.settings.root + path, 'utf8', function(err, data) {
|
||||
if(err) {
|
||||
console.log('ERROR: ' + err);
|
||||
return;
|
||||
} else {
|
||||
index = data;
|
||||
next(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.Gemini = class Gemini {
|
||||
constructor() {
|
||||
this.req = req;
|
||||
this.res = res;
|
||||
this.router = router;
|
||||
this.settings = {
|
||||
root: 'geminiroot/',
|
||||
index: 'index.gml',
|
||||
port: 1965
|
||||
};
|
||||
this.options = {
|
||||
key: fs.readFileSync('cert/localhost-key.pem'),
|
||||
cert: fs.readFileSync('cert/localhost-cert.pem'),
|
||||
passphrase: "rdeci3kombi",
|
||||
agent: false,
|
||||
requestCert: true,
|
||||
rejectUnauthorized: false,
|
||||
ciphers: 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS',
|
||||
honorCipherOrder: true,
|
||||
secureOptions: constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_SSLv2,
|
||||
};
|
||||
this.server = tls.createServer(this.options, function(c) {
|
||||
c.on('end', function() {
|
||||
//do nothing
|
||||
});
|
||||
|
||||
c.on('error', function(err) {
|
||||
let timestamp = Date.now();
|
||||
let date_ob = new Date(timestamp);
|
||||
let utc = date_ob.toUTCString();
|
||||
|
||||
console.log(`[${utc}] ${c.remoteAddress} ${req.path} ERR: ${err}`);
|
||||
});
|
||||
|
||||
c.on('data', function(data) {
|
||||
var timestamp = Date.now();
|
||||
|
||||
let date_ob = new Date(timestamp);
|
||||
let date = date_ob.getDate();
|
||||
let month = date_ob.getMonth() + 1;
|
||||
let year = date_ob.getFullYear();
|
||||
let hour = date_ob.getHours();
|
||||
let minute = date_ob.getMinutes();
|
||||
let second = date_ob.getSeconds();
|
||||
let utc = date_ob.toUTCString();
|
||||
|
||||
req.setClientCert(c.getPeerCertificate());
|
||||
req.setRawRequest(data);
|
||||
req.parseRequest();
|
||||
req.setClientIP(c.remoteAddress);
|
||||
req.setClientPort(c.remotePort);
|
||||
req.setClientFamily(c.remoteFamily);
|
||||
res.setSocket(c);
|
||||
router.set(req.path, req, res);
|
||||
c.end();
|
||||
var timestamp2 = Date.now();
|
||||
var requestTime = timestamp2 - timestamp;
|
||||
console.log(`[${utc}] ${c.remoteAddress} ${req.path} - \x1b[33m${res.status}\x1b[0m - \x1b[36m${requestTime}ms\x1b[0m`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
listen() {
|
||||
this.server.listen(this.settings.port, function() {
|
||||
console.log('Gemini Server Bound');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user