HTTPServer.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import http from "http"
  2. import {URL} from "url"
  3. import fs from "fs"
  4. import path from "path"
  5. function parseAccept(head: string): string[]{
  6. let clientAccept = head.split(";");
  7. if(!(0 in clientAccept)){
  8. this.res.writeHead(400);
  9. this.res.end("Problem with accept header");
  10. return;
  11. }
  12. let acc = []
  13. for(let it of clientAccept){
  14. acc = acc.concat(acc, it.split(","))
  15. }
  16. return acc;
  17. }
  18. const playerpage: string = fs.readFileSync(
  19. path.join(__dirname, "../../obs/index.html"), "utf8");
  20. export class HTTPRequest{
  21. private req: http.IncomingMessage;
  22. private res: http.ServerResponse;
  23. private url: URL;
  24. constructor(req: http.IncomingMessage,res: http.ServerResponse){
  25. this.req = req;
  26. this.res = res;
  27. this.url = new URL(req.url, `http://${req.headers.host}`);
  28. }
  29. notFound(){
  30. this.res.writeHead(404);
  31. this.res.end("Not Found");
  32. }
  33. internalError(){
  34. this.res.writeHead(500);
  35. this.res.end("Internal Server Error");
  36. }
  37. getPlayerIndex(){
  38. this.res.writeHead(200);
  39. this.res.end(playerpage.replace("<$wsport$>",
  40. window.settings.options.wsport.toString()));
  41. }
  42. async getMP4(){
  43. let id = this.url.pathname.slice(5);
  44. console.log(this.req.headers);
  45. if(this.req.headers.accept){
  46. let formats = parseAccept(this.req.headers.accept);
  47. console.log(formats);
  48. if(!(formats.includes("video/*")
  49. || formats.includes("video/mp4")
  50. || formats.includes("*/*"))){
  51. this.res.writeHead(400);
  52. this.res.end("mp4 not supported");
  53. return;
  54. }
  55. }
  56. if(id in window.settings.options.alerts){
  57. console.log(id);
  58. let path = window.settings.options.alerts[id].filepath;
  59. try {
  60. let stat = await fs.promises.stat(path);
  61. if(!stat.isFile()){
  62. throw new Error("This is not a file");
  63. }
  64. if(this.req.headers.range &&
  65. this.req.headers.range.startsWith("bytes=") ){
  66. let pos =
  67. this.req.headers.range.slice(6).split("-");
  68. let start = parseInt(pos[0], 10);
  69. let total = stat.size;
  70. let end = pos[1] ? parseInt(pos[1], 10) : total - 1;
  71. this.res.setHeader("Accept-Ranges", "bytes");
  72. this.res.setHeader("Content-Type", "video/mp4");
  73. this.res.setHeader("Content-Range",
  74. `bytes ${start}-${end}/${total}`);
  75. let stream = fs.createReadStream(path, {
  76. start,
  77. end
  78. });
  79. this.res.writeHead(206);
  80. stream.pipe(this.res);
  81. return
  82. }else{
  83. let stream = fs.createReadStream(path);
  84. this.res.setHeader("Content-Type", "video/mp4");
  85. this.res.writeHead(200);
  86. stream.pipe(this.res);
  87. return;
  88. }
  89. } catch(err){
  90. this.internalError();
  91. return
  92. }
  93. }else{
  94. this.notFound();
  95. return
  96. }
  97. }
  98. getHandler(){
  99. if(this.url.pathname.startsWith("/mp4/")){
  100. return this.getMP4();
  101. }else if(this.url.pathname == "/"){
  102. return this.getPlayerIndex();
  103. }else{
  104. return this.notFound();
  105. }
  106. }
  107. parse(){
  108. if(this.req.method == "GET"){
  109. return this.getHandler();
  110. }else{
  111. return this.notFound();
  112. }
  113. }
  114. }
  115. export class HTTPServer {
  116. private port: number;
  117. private server?: http.Server;
  118. private closing: boolean;
  119. constructor(){
  120. this.port = window.settings.options.httpport || 8050;
  121. this.closing = false;
  122. }
  123. setPort(port: number){
  124. if(this.server && this.server.listening){
  125. if(!this.closing){
  126. this.closing = true;
  127. this.server.close(()=>{
  128. this.port = port;
  129. this.closing = false;
  130. this.listen();
  131. })
  132. }
  133. }else{
  134. this.port = port;
  135. }
  136. }
  137. create(){
  138. this.server = http.createServer((req, res) =>{
  139. let request = new HTTPRequest(req, res);
  140. request.parse();
  141. });
  142. }
  143. listen(){
  144. if(this.server){
  145. this.server.listen(this.port)
  146. }else{
  147. throw new Error("Listen before create")
  148. }
  149. }
  150. }
  151. export default HTTPServer;