App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
undisclosed
2023-01-08 e27ab178fa3a2f967823c1bfc81951086e15b642
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
    Calypso - Media Player Remote Control via HTTP for Raspberry Pi
    Copyright (C) 2021-2023  Ulrich Hilger
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
 
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
 
package de.uhilger.calypso.http;
 
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.calypso.actor.PlayActor;
import de.uhilger.calypso.actor.ShellActor;
import de.uhilger.calypso.actor.StopServerActor;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
 
/**
 * Der ApiHandler ist die proprietaer fuer Calypso vorgesehene 
 * Weise, HTTP-Anfragen zu verarbeiten.
 *
 * Der ApiHandler ist ein HttpHandler, der vom Server ueber die 
 * gesamte Laufzeit des Programmes hinweg gehalten wird. Deswegen 
 * beschraenkt sich der Programmcode des ApiHandlers auf die
 * Verteilung der Kommandos auf Aktoren. Die Aktoren werden je nach 
 * Bedarf instanziiert und enthalten zusammengenommen den Code 
 * des Anwendungskerns.
 *
 * @author Ulrich Hilger
 */
public class ApiHandler extends HttpApi {
 
  public static final int PLAYERCMD = 2;
  public static final int SERVERCMD = 3;
  public static final String PLAY = "play";
  public static final String PAUSE = "pause";
  public static final String SEEK = "seek";
  public static final String STOP = "stop";
  public static final String SERVER = "server";
  public static final String PING = "ping";
  
  public static final String PLAYER = "player-proc";
  
  /**
   * Die HTTP-Anfrage ausführen
   * 
   * WICHTIG: Die HTTP-Parameter aus dem Query-Teil muessen in 
   * der Reihenfolge sein, die vom Shell-Skript erwartet wird. 
   *
   * @param elems die Elemente des URI-Pfads
   * @param parameter die Parameter des Query-Teils der URI
   * @param exchange das Objekt mit Infos zum HTTP-Aufruf
   * @return die Antwort, die gesendet werden soll
   */
  @Override
  protected String process(String[] elems, Map parameter, HttpExchange exchange) {
    String antwort;
    Object o;
 
    switch (elems[PLAYERCMD]) {
      case PLAY:
        PlayActor a = new PlayActor();
        o = a.run(parameter);
        if (o instanceof Process) {
          exchange.getHttpContext().getAttributes().put(PLAYER, o);
          antwort = "Abspielprozess gestartet.";
        } else {
          // kein Prozess, es ist etwas schief gelaufen
          antwort = "Abspielen konnte nicht gestartet werden.";
        }
        break;
 
      case PAUSE:
      case SEEK:
        ShellActor pa = new ShellActor();      
        try {
          pa.run(getSkriptDir(exchange), elems[PLAYERCMD], toShellParams(parameter));
          antwort = elems[PLAYERCMD] + " ausgefuehrt";
        } catch (IOException ex) {
          Logger.getLogger(ApiHandler.class.getName()).log(Level.SEVERE, null, ex);
          antwort = "Fehler bei der Ausfuehrung von " + elems[PLAYERCMD];
        }        
        break;
 
      case STOP:
        o = exchange.getHttpContext().getAttributes().get(PLAYER);
        if(o instanceof Process) {
          Process p = (Process) o;
          p.destroy();
          antwort = "Player gestoppt.";
        } else {
          antwort = "Es wurde kein Player-Prozess zum Stoppen gefunden.";
        }
        break;
        
      case SERVER:
        if(elems[SERVERCMD].equals(STOP)) {
          try {
            antwort = "Calypso: Der Server wird angehalten und die App beendet.";
            sendResponse(exchange, antwort);
            new StopServerActor().run(exchange.getHttpContext());
          } catch (IOException ex) {
            Logger.getLogger(ApiHandler.class.getName()).log(Level.SEVERE, null, ex);
            antwort = "Fehler: " + ex.getLocalizedMessage();
          }
        } else {
          antwort = elems[SERVERCMD] + " ist ein unbekanntes Serverkommando";
        }
        break;
        
      case PING:
        antwort = elems[PLAYERCMD];
        break;
        
      default:
        antwort = "Kommando " + elems[PLAYERCMD] + " unbekannt";
        break;
    }
 
    return antwort;
  }
  
  private String[] toShellParams(Map parameter) {
    Collection<String> c = parameter.values();
    return c.toArray(String[]::new);
  }
 
  private String getSkriptDir(HttpExchange exchange) {
    HttpContext context = exchange.getHttpContext();
    Object o = context.getAttributes().get(Server.SKRIPT_DIR);
    if (o instanceof String) {
      return (String) o;
    } else {
      // kein Skript-Dir
      return "";
    }
  }
}