package aQute.jpm.lib; import static aQute.lib.io.IO.collect; import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketTimeoutException; import aQute.lib.io.IO; import aQute.lib.io.IOConstants; public class Service { static final int BUFFER_SIZE = IOConstants.PAGE_SIZE * 16; final ServiceData data; final JustAnotherPackageManager jpm; final File lock; Service(JustAnotherPackageManager jpm, ServiceData data) throws Exception { this.jpm = jpm; this.data = data; this.lock = new File(data.lock); } public String start() throws Exception { return start(false); } public String start(boolean force) throws Exception { if (lock.exists()) { if (!force) return "Already running"; IO.delete(lock); Thread.sleep(2000); } if (lock.createNewFile()) { jpm.platform.chown(data.user, false, lock); try { Thread.sleep(1000); int result = jpm.platform.launchService(data); if (result != 0) return "Could not launch service " + data.name + " return value " + result; long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 10000) { Thread.sleep(100); if (getPort() != -1) return null; } IO.delete(lock); return "Could not establish a link to the service, likely failed to start"; } catch (Throwable t) { IO.delete(lock); return String.format("Failed to start %s for %s", data.name, t); } } return "Could not create lock file"; } public String stop() throws Exception { if (lock.exists()) { if (!lock.canWrite()) { return String.format("Cannot write lock %s", data.lock); } try { send(getPort(), "STOP"); for (int i = 0; i < 20; i++) { if (!lock.exists()) return null; Thread.sleep(500); } return "Lock was not deleted by service in time (waited 10 secs)"; } finally { IO.delete(lock); } } return "Not running"; } public String status() throws Exception { if (lock.canWrite() && lock.exists()) return send(getPort(), "STATUS"); return null; } private String send(int port, String m) throws Exception { if (port == -1) return "Invalid port"; byte data[] = m.getBytes(UTF_8); DatagramPacket p = new DatagramPacket(data, 0, data.length, InetAddress.getLoopbackAddress(), port); DatagramSocket dsocket = new DatagramSocket(); dsocket.setReceiveBufferSize(5000); dsocket.setSoTimeout(5000); try { dsocket.send(p); byte[] buffer = new byte[BUFFER_SIZE]; DatagramPacket dp = new DatagramPacket(buffer, BUFFER_SIZE); dsocket.receive(dp); return new String(dp.getData(), dp.getOffset(), dp.getLength(), UTF_8); } catch (SocketTimeoutException stoe) { return "Timed out"; } finally { dsocket.close(); } } int getPort() { try { String l = collect(data.lock); String parts[] = l.split(":"); return Integer.parseInt(parts[0]); } catch (Exception e) { // e.printStackTrace(); return -1; } } int getPid() throws IOException { try { String l = collect(data.lock); String parts[] = l.split(":"); return Integer.parseInt(parts[1]); } catch (Exception e) { return -1; } } public boolean isRunning() { return lock.exists(); } @Override public String toString() { return data.name; } public ServiceData getServiceData() { return data; } public String update(ServiceData data) throws Exception { return jpm.createService(data, true); } public String trace(boolean b) throws Exception { if (!isRunning()) return "Not running"; if (b) send(getPort(), "TRACE-ON"); else send(getPort(), "TRACE-OFF"); return null; } public void remove() throws Exception { try { stop(); } catch (Exception e) {} IO.deleteWithException(new File(data.sdir)); jpm.platform.deleteService(data); } public void clear() { IO.delete(new File(data.log)); File work = new File(data.work); IO.delete(work); try { IO.mkdirs(work); } catch (IOException e) { throw new RuntimeException(e); } } }