summaryrefslogtreecommitdiff
path: root/sync.ha
diff options
context:
space:
mode:
Diffstat (limited to 'sync.ha')
-rw-r--r--sync.ha195
1 files changed, 195 insertions, 0 deletions
diff --git a/sync.ha b/sync.ha
new file mode 100644
index 0000000..de35dc5
--- /dev/null
+++ b/sync.ha
@@ -0,0 +1,195 @@
+use fmt;
+use log;
+use net;
+use net::tcp;
+use net::ip;
+use types;
+use bufio;
+use shlex;
+use io;
+use unix::poll;
+use unix::signal;
+use encoding::utf8;
+use strings;
+use regex;
+use strconv;
+use fs;
+use os;
+use strings;
+
+type nofreefd = !void;
+type invalidquery = !str;
+type quit = void;
+type saveposerr = !(fs::error | io::error);
+type error = !(invalidquery | shlex::syntaxerr | utf8::invalid | strconv::overflow | strconv::invalid | saveposerr);
+
+fn savepos(filename: str, position: str) (void | saveposerr) = {
+ let f = os::open(filename, fs::flag::WRONLY, fs::flag::CREATE, fs::flag::TRUNC)?;
+ defer io::close(f)!;
+ os::chmod(filename, fs::mode::USER_RW | fs::mode::GROUP_R | fs::mode::OTHER_R)?;
+ fmt::fprint(f, position)?;
+};
+
+fn handlequery(query: const []u8) (void | []u8 | quit | error) = {
+ log::printfln("query: {}", strings::fromutf8_unsafe(query));
+ let s = strings::fromutf8(query)?;
+ let spl = shlex::split(s)?;
+ defer strings::freeall(spl);
+ if (len(spl) == 0) {
+ return "Empty query": invalidquery;
+ };
+ switch (spl[0]) {
+ case "save" =>
+ if (len(spl) != 3) {
+ return "save takes 2 arguments (filename, position)": invalidquery;
+ };
+ //let re = regex::compile("[0-9]{2}:[0-9]{2}:[0-9]{2}")?;
+ //defer regex::finish(&re);
+ //const res = regex::replace(&re, spl[2], "")?;
+ //if (res != "") {
+ // return "save position format: hh:mm:ss": invalidquery;
+ //};
+ //let re2 = regex::compile("[0-9]{2}")?;
+ //defer regex::finish(&re2);
+ //const result = regex::findall(&re2, spl[2]);
+ //if (len(result) != 3) {
+ // return "save position format: hh:mm:ss": invalidquery;
+ //};
+ //if (strconv::stou(result[1][0].content)? >= 60 || strconv::stou(result[2][0].content)? >= 60) {
+ // return "save position format: hh:mm:ss (mm < 60 && ss < 60)": invalidquery;
+ //};
+ //log::printfln("Saving {} with position {}", spl[1], spl[2]);
+ savepos(spl[1], spl[2])?;
+ case "get" =>
+ if (len(spl) != 2) {
+ return "get takes 1 argument (filename)": invalidquery;
+ };
+ let f = os::open(spl[1])?;
+ let buf = io::drain(f)?;
+ log::printfln("sending buf: {}", strings::fromutf8_unsafe(buf));
+ return buf;
+ case "quit" =>
+ return quit;
+ case =>
+ return "Unknown query": invalidquery;
+ };
+};
+
+fn logerror(err: (void | error)) void = {
+ match (err) {
+ case void =>
+ return;
+ case let e: invalidquery =>
+ log::println(e);
+ case shlex::syntaxerr =>
+ log::println("Syntax error");
+ case utf8::invalid =>
+ log::println("Invalid utf8");
+ case let e: strconv::error =>
+ log::println(strconv::strerror(e));
+ case let e: fs::error =>
+ log::println(fs::strerror(e));
+ case let e: io::error =>
+ log::println(io::strerror(e));
+ };
+};
+
+fn close(pollfds: []poll::pollfd) void = {
+ for (let i = 2z; i < len(pollfds); i += 1) {
+ if (pollfds[i].fd >= 0) {
+ net::close(pollfds[i].fd)!;
+ };
+ };
+ //if (pollfds[0].fd >= 0) net::close(pollfds[0].fd)!;
+};
+
+fn nextfreefd(fds: []poll::pollfd) (size | nofreefd) = {
+ for (let i = 0z; i < len(fds); i += 1) {
+ if (fds[i].fd < 0) {
+ return i;
+ };
+ };
+ return nofreefd;
+};
+
+export fn main() void = {
+ let addr = ip::parse("127.0.0.1")!;
+ let sock = tcp::listen(addr, 6789u16)!;
+ defer net::close(sock)!;
+
+ signal::block(signal::sig::INT);
+ let sfd = signal::signalfd(signal::sig::INT)!;
+
+ // Use array, growable slice doesn't work with poll (new accept socket
+ // fds overwrite old accept socket fds for some reason)
+ let pollfds: [200]poll::pollfd = [
+ poll::pollfd {
+ fd = sock,
+ events = poll::event::POLLIN,
+ ...
+ },
+ poll::pollfd {
+ fd = sfd,
+ events = poll::event::POLLIN,
+ ...
+ }, poll::pollfd{fd = -1, ...}...
+ ];
+
+ defer close(pollfds);
+
+ for (true) {
+ let i = poll::poll(pollfds, poll::INDEF)!;
+ if (i > 0) {
+ if (pollfds[0].revents & poll::event::POLLIN != 0) {
+ let s= tcp::accept(sock)!;
+ const fd = nextfreefd(pollfds)!;
+ pollfds[fd] = poll::pollfd {
+ fd = s,
+ events = poll::event::POLLIN,
+ ...
+ };
+ };
+ if (pollfds[1].revents & poll::event::POLLIN != 0) {
+ signal::read(pollfds[1].fd)!;
+ break;
+ };
+ for (let j = 2z; j < len(pollfds); j += 1) {
+ if (pollfds[j].revents & poll::event::POLLIN != 0) {
+ let s = pollfds[j].fd;
+ log::printfln("client at index {} with fd {}", j, s: int);
+ let line = match (bufio::scanline(s)) {
+ case let line: []u8 =>
+ yield line;
+ case io::EOF =>
+ log::printfln("Closing connection to client at index {} with fd {}", j, s: int);
+ net::close(s)!;
+ pollfds[j].fd = -1;
+ break;
+ case let e: io::error =>
+ log::println(io::strerror(e));
+ break;
+ };
+ defer free(line);
+ match (handlequery(line)) {
+ case let e: error =>
+ logerror(e);
+ case quit =>
+ log::printfln("Closing connection to client at index {} with fd {}", j, s: int);
+ net::close(s)!;
+ pollfds[j].fd = -1;
+ case void =>
+ yield;
+ case let buf: []u8 =>
+ defer free(buf);
+ match (fmt::fprintfln(s, "{}", strings::fromutf8_unsafe(buf))) {
+ case let e: io::error =>
+ log::println(io::strerror(e));
+ case size =>
+ yield;
+ };
+ };
+ };
+ };
+ };
+ };
+};