Sagitta/Sagitta.hx

143 lines
3.7 KiB
Haxe

/*
SAGITTA -- the arrow
gemini fetcher
named so because it requires some "bow" code to shoot it well
but it can be rebound off of redirects,
shot through tls,
and find any links in its path,
for easier management by the archer
*/
import Sys.getChar;
import Sys.systemName;
#if Windows
import Sys.command;
#end
import Sys.print;
import Sys.println;
import sys.net.Socket;
import sys.ssl.Socket as SSL_Socket;
import sys.net.Host;
import JanBug.pbug;
//import Std.string;
class Sagitta {
static final timeout_short=0.5; //in seconds, time before first attempt fails
static final timeout_long=1; //in seconds, time before second attempt fails
static final nl="\n"; //newline
static public function main(){
/*
* if the result isn't intended to run on windows,
* then assume it works with ansi escapes
* adding windows flag just allows
*/
#if Windows
if(systemName()=="Windows"){
command("%userprofile%\\documents\\C\\fixcon10.exe");
};
#end
stuff("gemini://tilde.pink/~jan6");
pbug("press any key to continue","info");
getChar(false);
};
// static public function stuff(url:String,?redirect:Bool=false) {
static public function stuff(url:String) {
var redirect:Bool=false;
//convenience variables to avoid quotes
final error="error";
final warn ="warn";
final info="info";
final debug="debug";
pbug("requesting: "+url,debug,true);
var text=false;
var nl=Sagitta.nl; //newline
var buf=new haxe.io.BytesBuffer();
var timeout_short=Sagitta.timeout_short;
var timeout_long =Sagitta.timeout_long;
//don't verify now, since want self-signed and whatnot to be accepted
SSL_Socket.DEFAULT_VERIFY_CERT=false;
var socket = new SSL_Socket();
socket.connect(new Host(url.split("/")[2]), 1965);
socket.setTimeout(timeout_short); //timeout in seconds
//pbug('timeout set to short: $timeout_short seconds');
socket.setFastSend(true); //not needed, not sure if matters
//Sys.sleep(2); //doesn't help
pbug("writing request");
socket.write('$url\r\n');
socket.output.flush(); //shouldn't be needed, right?
pbug("request written");
socket.waitForRead();
var header=socket.input.read(1).toString();
if(header!=null){
pbug("reading header");
header+=socket.input.readUntil("\r".code);
socket.input.readByte();
if(header.split("")[0]=="3"){
var new_url=header.split("\r")[0].split(" ")[1];
pbug("redirect "+new_url,info);
stuff(new_url);
redirect=true;
// stuff(new_url,true);
}
else if(header.split("")[0]=="2"){
var mime=header.split(" ")[1];
if(mime.split("/")[0].toLowerCase()=="text"){
pbug("mimetype is text",debug);
};
};
else println(header);
if(!redirect){pbug("header read");};
try {
buf.add(socket.input.read(1));
if(buf!=null){
pbug("reading body");
if(text){
while(true){
buf.addString(socket.input.readLine()+nl);
};
}
else {
while(true){
buf.add(socket.input.read(1));
//var a=socket.input.read(5);
};
};
};
pbug("body read");
//} catch (e:Any) { //since haxe 4.1 reccommended to drop wildcard type
}
catch (e:haxe.io.Error) {
if(e == haxe.io.Error.Blocked){
pbug("I/O Blocked, attempting with longer timeout",warn);
socket.setTimeout(timeout_long); //timeout in seconds
pbug('timeout set to long: $timeout_long seconds');
pbug("reading body");
try {
while(true){
buf.add(socket.input.read(1));
};
pbug("body read");
}
catch (e:haxe.io.Error) {
if(e == haxe.io.Error.Blocked){
pbug("I/O Blocked!",error);
};
}
};
}
catch (e:haxe.io.Eof) {
print(buf.getBytes());
if(!redirect){pbug('EOF of $url',info);};
};
};
socket.close();
//*/
}
}