From 9d61f22844bdfcbe983976aaf5176d08e741a6de Mon Sep 17 00:00:00 2001 From: Holger Cremer Date: Thu, 11 Jun 2015 20:47:03 +0200 Subject: a simple cli interface to send barcodes --- .gitignore | 1 + src/cli/.gitignore | 1 + src/cli/Makefile | 11 + src/cli/cli-interface.vala | 19 ++ src/cli/cli.vala | 28 +++ src/cli/main.vala | 65 ++++++ src/scanner-session/Makefile | 2 +- src/scanner-session/scannersession.vala | 388 ++++++++++++++++---------------- 8 files changed, 322 insertions(+), 193 deletions(-) create mode 100644 src/cli/.gitignore create mode 100644 src/cli/Makefile create mode 100644 src/cli/cli-interface.vala create mode 100644 src/cli/cli.vala create mode 100644 src/cli/main.vala diff --git a/.gitignore b/.gitignore index 0f922c6..359056d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ shop.db ktt-shopsystem.cfg config.mk config.h +.DS_Store diff --git a/src/cli/.gitignore b/src/cli/.gitignore new file mode 100644 index 0000000..573c0c4 --- /dev/null +++ b/src/cli/.gitignore @@ -0,0 +1 @@ +cli diff --git a/src/cli/Makefile b/src/cli/Makefile new file mode 100644 index 0000000..f042ca8 --- /dev/null +++ b/src/cli/Makefile @@ -0,0 +1,11 @@ +all: cli + @echo > /dev/null + +cli: main.vala cli.vala cli-interface.vala ../config/config-interface.vala + valac -X -w -o $@ --pkg linux --pkg posix --pkg gio-2.0 $^ + + +clean: + rm -rf cli + +.PHONY: all clean diff --git a/src/cli/cli-interface.vala b/src/cli/cli-interface.vala new file mode 100644 index 0000000..879ad27 --- /dev/null +++ b/src/cli/cli-interface.vala @@ -0,0 +1,19 @@ +/* Copyright 2015, Holger Cremer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.Cli")] +public interface Cli : Object { + public abstract signal void received_barcode(string barcode); +} diff --git a/src/cli/cli.vala b/src/cli/cli.vala new file mode 100644 index 0000000..bc6fe9d --- /dev/null +++ b/src/cli/cli.vala @@ -0,0 +1,28 @@ +/* Copyright 2015, Holger Cremer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[DBus (name = "io.mainframe.shopsystem.Cli")] +public class CliImpl { + + public signal void received_barcode(string barcode); + + public CliImpl() { + } + + public void send(string msg) { + stdout.printf("Sending: %s\n", msg); + received_barcode(msg); + } +} diff --git a/src/cli/main.vala b/src/cli/main.vala new file mode 100644 index 0000000..a85cbc7 --- /dev/null +++ b/src/cli/main.vala @@ -0,0 +1,65 @@ +/* Copyright 2015, Holger Cremer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +CliImpl cli; +MainLoop ml; +string[] commands; + +public static int main(string[] args) { + if (args.length == 1) { + stdout.printf("Nothing to send.\nUsage: %s \nExample: %s \"USER 1\" \"LOGOUT\"\n", args[0], args[0]); + return 0; + } + commands = args[1:args.length]; + + cli = new CliImpl(); + Bus.own_name( + BusType.SESSION, + "io.mainframe.shopsystem.Cli", + BusNameOwnerFlags.NONE, + on_bus_aquired, + on_name_aquired, + () => stderr.printf("Could not aquire name\n")); + + ml = new MainLoop(); + + ml.run(); + + return 0; +} + +void on_name_aquired() { + foreach (string cmd in commands) { + cli.send(cmd); + } + + // wait a minimal amount of time, to ensure the event was sent + TimeoutSource time = new TimeoutSource (100); + time.set_callback (() => { + ml.quit (); + return false; + }); + time.attach (ml.get_context ()); + +} + +void on_bus_aquired(DBusConnection con) { + try { + con.register_object("/io/mainframe/shopsystem/cli", cli); + } catch(IOError e) { + stderr.printf("Could not register service\n"); + } + +} \ No newline at end of file diff --git a/src/scanner-session/Makefile b/src/scanner-session/Makefile index 4d8e8f8..68a906a 100644 --- a/src/scanner-session/Makefile +++ b/src/scanner-session/Makefile @@ -1,7 +1,7 @@ all: scanner-session @echo > /dev/null -scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../serial-device/serial-device-interface.vala ../audio/audio-interface.vala ../price.vapi +scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../serial-device/serial-device-interface.vala ../cli/cli-interface.vala ../audio/audio-interface.vala ../price.vapi valac -X -w -o $@ --pkg gio-2.0 $^ clean: diff --git a/src/scanner-session/scannersession.vala b/src/scanner-session/scannersession.vala index 9e87682..8d89593 100644 --- a/src/scanner-session/scannersession.vala +++ b/src/scanner-session/scannersession.vala @@ -15,196 +15,200 @@ [DBus (name = "io.mainframe.shopsystem.ScannerSession")] public class ScannerSessionImplementation { - private int user = 0; - private string name = "Guest"; - private bool logged_in = false; - private bool disabled = false; - private string theme = "beep"; - - private Database db; - private AudioPlayer audio; - private SerialDevice dev; - - public signal void msg(MessageType type, string message); - public signal void popup(string title, string message); - - public ScannerSessionImplementation() { - try { - db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); - dev = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.SerialDevice", "/io/mainframe/shopsystem/device"); - audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); - - dev.received_barcode.connect(handle_barcode); - } catch(IOError e) { - error("IOError: %s\n", e.message); - } - } - - private void send_message(MessageType type, string format, ...) { - var arguments = va_list(); - var message = format.vprintf(arguments); - - msg(type, message); - } - - private void logout() { - logged_in = false; - } - - private bool login(int user) throws IOError { - this.user = user; - try { - this.name = db.get_username(user); - this.disabled = db.get_user_auth(user).disabled; - } catch(DatabaseError e) { - send_message(MessageType.ERROR, "Error (user=%d): %s", user, e.message); - return false; - } - this.logged_in = true; - - try { - this.theme = audio.get_random_user_theme(); - } catch(IOError e) { - this.theme = "beep"; - } - - return true; - } - - private void handle_barcode(string scannerdata) { - try { - stdout.printf("scannerdata: %s\n", scannerdata); - if(interpret(scannerdata)) - dev.blink(1000); - } catch(IOError e) { - send_message(MessageType.ERROR, "IOError: %s", e.message); - } catch(DatabaseError e) { - send_message(MessageType.ERROR, "DatabaseError: %s", e.message); - } - } - - private bool interpret(string scannerdata) throws DatabaseError, IOError { - if(scannerdata.has_prefix("USER ")) { - string str_id = scannerdata.substring(5); - int32 id = int.parse(str_id); - - /* check if scannerdata has valid format */ - if(scannerdata != "USER %d".printf(id)) { - audio.play_system("error.ogg"); - send_message(MessageType.ERROR, "Invalid User ID: %s", scannerdata); - return false; - } - - if(logged_in) { - send_message(MessageType.WARNING, "Last user forgot to logout"); - logout(); - } - - if(login(id)) { - audio.play_user(theme, "login"); - send_message(MessageType.INFO, "Login: %s (%d)", name, user); - return true; - } else { - audio.play_system("error.ogg"); - send_message(MessageType.ERROR, "Login failed (User ID = %d)", id); - return false; - } - } else if(scannerdata == "GUEST") { - if(logged_in) { - send_message(MessageType.WARNING, "Last user forgot to logout"); - logout(); - } - - if(login(0)) { - audio.play_user(theme, "login"); - send_message(MessageType.INFO, "Login: %s (%d)", name, user); - return true; - } else { - audio.play_system("error.ogg"); - send_message(MessageType.ERROR, "Login failed (User ID = 0)"); - return false; - } - } else if(scannerdata == "UNDO") { - if(!logged_in) { - audio.play_system("error.ogg"); - send_message(MessageType.ERROR, "Can't undo if not logged in!"); - return false; - } else { - string product = db.undo(user); - - if(product != "") { - audio.play_user(theme, "purchase"); - send_message(MessageType.INFO, "Removed purchase of %s", product); - return true; - } else { - audio.play_user(theme, "error"); - send_message(MessageType.ERROR, "Couldn't undo last purchase!"); - return false; - } - } - } else if(scannerdata == "LOGOUT") { - if(logged_in) { - audio.play_user(theme, "logout"); - send_message(MessageType.INFO, "Logout!"); - logout(); - return true; - } - - return false; - } else { - uint64 id = 0; - scannerdata.scanf("%llu", out id); - - /* check if scannerdata has valid format */ - if(scannerdata != "%llu".printf(id) && scannerdata != "%08llu".printf(id) && scannerdata != "%013llu".printf(id)) { - audio.play_user(theme, "error"); - send_message(MessageType.ERROR, "invalid product: %s", scannerdata); - return false; - } - - string name = "unknown product"; - - try { - name = db.get_product_name(id); - } catch(IOError e) { - audio.play_user(theme, "error"); - send_message(MessageType.ERROR, "Internal Error!"); - return false; - } catch(DatabaseError e) { - if(e is DatabaseError.PRODUCT_NOT_FOUND) { - audio.play_user(theme, "error"); - var msg = "Error: unknown product: %llu".printf(id); - send_message(MessageType.ERROR, msg); - popup("Attention", msg); - } else { - audio.play_user(theme, "error"); - send_message(MessageType.ERROR, "Error: %s", e.message); - } - return false; - } - - if(!logged_in) { - var mprice = db.get_product_price(1, id); - var gprice = db.get_product_price(0, id); - var msg = @"article info: $name (Member: $mprice €, Guest: $gprice €)"; - audio.play_system("error.ogg"); - send_message(MessageType.INFO, msg); - send_message(MessageType.ERROR, "Login required for purchase!"); - popup("Attention", "%s\nLogin required for purchase!".printf(msg)); - - return false; - } - - if(db.buy(user, id)) { - var price = db.get_product_price(user, id); - audio.play_user(theme, "purchase"); - send_message(MessageType.INFO, @"article bought: $name ($price €)"); - return true; - } else { - audio.play_user(theme, "error"); - send_message(MessageType.ERROR, "purchase failed!"); - return false; - } - } - } + private int user = 0; + private string name = "Guest"; + private bool logged_in = false; + private bool disabled = false; + private string theme = "beep"; + + private Database db; + private AudioPlayer audio; + private SerialDevice dev; + private Cli cli; + + + public signal void msg(MessageType type, string message); + public signal void popup(string title, string message); + + public ScannerSessionImplementation() { + try { + db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database"); + dev = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.SerialDevice", "/io/mainframe/shopsystem/device"); + cli = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Cli", "/io/mainframe/shopsystem/cli"); + audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio"); + + dev.received_barcode.connect(handle_barcode); + cli.received_barcode.connect(handle_barcode); + } catch(IOError e) { + error("IOError: %s\n", e.message); + } + } + + private void send_message(MessageType type, string format, ...) { + var arguments = va_list(); + var message = format.vprintf(arguments); + + msg(type, message); + } + + private void logout() { + logged_in = false; + } + + private bool login(int user) throws IOError { + this.user = user; + try { + this.name = db.get_username(user); + this.disabled = db.get_user_auth(user).disabled; + } catch(DatabaseError e) { + send_message(MessageType.ERROR, "Error (user=%d): %s", user, e.message); + return false; + } + this.logged_in = true; + + try { + this.theme = audio.get_random_user_theme(); + } catch(IOError e) { + this.theme = "beep"; + } + + return true; + } + + private void handle_barcode(string scannerdata) { + try { + stdout.printf("scannerdata: %s\n", scannerdata); + if(interpret(scannerdata)) + dev.blink(1000); + } catch(IOError e) { + send_message(MessageType.ERROR, "IOError: %s", e.message); + } catch(DatabaseError e) { + send_message(MessageType.ERROR, "DatabaseError: %s", e.message); + } + } + + private bool interpret(string scannerdata) throws DatabaseError, IOError { + if(scannerdata.has_prefix("USER ")) { + string str_id = scannerdata.substring(5); + int32 id = int.parse(str_id); + + /* check if scannerdata has valid format */ + if(scannerdata != "USER %d".printf(id)) { + audio.play_system("error.ogg"); + send_message(MessageType.ERROR, "Invalid User ID: %s", scannerdata); + return false; + } + + if(logged_in) { + send_message(MessageType.WARNING, "Last user forgot to logout"); + logout(); + } + + if(login(id)) { + audio.play_user(theme, "login"); + send_message(MessageType.INFO, "Login: %s (%d)", name, user); + return true; + } else { + audio.play_system("error.ogg"); + send_message(MessageType.ERROR, "Login failed (User ID = %d)", id); + return false; + } + } else if(scannerdata == "GUEST") { + if(logged_in) { + send_message(MessageType.WARNING, "Last user forgot to logout"); + logout(); + } + + if(login(0)) { + audio.play_user(theme, "login"); + send_message(MessageType.INFO, "Login: %s (%d)", name, user); + return true; + } else { + audio.play_system("error.ogg"); + send_message(MessageType.ERROR, "Login failed (User ID = 0)"); + return false; + } + } else if(scannerdata == "UNDO") { + if(!logged_in) { + audio.play_system("error.ogg"); + send_message(MessageType.ERROR, "Can't undo if not logged in!"); + return false; + } else { + string product = db.undo(user); + + if(product != "") { + audio.play_user(theme, "purchase"); + send_message(MessageType.INFO, "Removed purchase of %s", product); + return true; + } else { + audio.play_user(theme, "error"); + send_message(MessageType.ERROR, "Couldn't undo last purchase!"); + return false; + } + } + } else if(scannerdata == "LOGOUT") { + if(logged_in) { + audio.play_user(theme, "logout"); + send_message(MessageType.INFO, "Logout!"); + logout(); + return true; + } + + return false; + } else { + uint64 id = 0; + scannerdata.scanf("%llu", out id); + + /* check if scannerdata has valid format */ + if(scannerdata != "%llu".printf(id) && scannerdata != "%08llu".printf(id) && scannerdata != "%013llu".printf(id)) { + audio.play_user(theme, "error"); + send_message(MessageType.ERROR, "invalid product: %s", scannerdata); + return false; + } + + string name = "unknown product"; + + try { + name = db.get_product_name(id); + } catch(IOError e) { + audio.play_user(theme, "error"); + send_message(MessageType.ERROR, "Internal Error!"); + return false; + } catch(DatabaseError e) { + if(e is DatabaseError.PRODUCT_NOT_FOUND) { + audio.play_user(theme, "error"); + var msg = "Error: unknown product: %llu".printf(id); + send_message(MessageType.ERROR, msg); + popup("Attention", msg); + } else { + audio.play_user(theme, "error"); + send_message(MessageType.ERROR, "Error: %s", e.message); + } + return false; + } + + if(!logged_in) { + var mprice = db.get_product_price(1, id); + var gprice = db.get_product_price(0, id); + var msg = @"article info: $name (Member: $mprice €, Guest: $gprice €)"; + audio.play_system("error.ogg"); + send_message(MessageType.INFO, msg); + send_message(MessageType.ERROR, "Login required for purchase!"); + popup("Attention", "%s\nLogin required for purchase!".printf(msg)); + + return false; + } + + if(db.buy(user, id)) { + var price = db.get_product_price(user, id); + audio.play_user(theme, "purchase"); + send_message(MessageType.INFO, @"article bought: $name ($price €)"); + return true; + } else { + audio.play_user(theme, "error"); + send_message(MessageType.ERROR, "purchase failed!"); + return false; + } + } + } } -- cgit v1.2.3