1
+ import { Pool , ResultSetHeader , RowDataPacket } from "mysql2" ;
2
+ import { Util } from "./Util" ;
3
+ import { CONFIG } from "./config" ;
4
+
5
+ const mysql = require ( 'mysql2' ) ;
6
+
7
+ export class Database {
8
+
9
+ protected static instance : Database ;
10
+ protected pool : Pool ;
11
+
12
+ private constructor ( ) {
13
+
14
+ const dbConfig = CONFIG . database ;
15
+
16
+ this . pool = mysql . createPool ( {
17
+ host : dbConfig . host ,
18
+ port : dbConfig . port ,
19
+ user : dbConfig . user ,
20
+ password : dbConfig . password ,
21
+ database : 'streaming' ,
22
+ waitForConnections : true ,
23
+ connectionLimit : 10 ,
24
+ maxIdle : 10 , // max idle connections, the default value is the same as `connectionLimit`
25
+ idleTimeout : 60000 , // idle connections timeout, in milliseconds, the default value 60000
26
+ queueLimit : 0 ,
27
+ enableKeepAlive : true ,
28
+ keepAliveInitialDelay : 0
29
+ } ) ;
30
+ }
31
+
32
+ public static getInstance ( ) : Database {
33
+
34
+ if ( ! Database . instance ) {
35
+ Database . instance = new Database ( ) ;
36
+ }
37
+
38
+ return Database . instance ;
39
+ }
40
+
41
+ public async select < T > ( sql : string , parameters ?: unknown [ ] ) : Promise < T [ ] > {
42
+ const [ rows ] = await this . pool . promise ( ) . query ( sql , parameters ) ;
43
+ return rows as T [ ] ;
44
+ }
45
+
46
+ // contains affectedRows and lastInsertId properties.
47
+ public async update ( ) {
48
+ // TODO
49
+ }
50
+
51
+ async ping ( ) : Promise < boolean > {
52
+ await this . pool . promise ( ) . query ( "SELECT 1" ) ;
53
+ return true ;
54
+ }
55
+
56
+ async checkIfChannelNameAvailable ( name : string ) : Promise < boolean > {
57
+
58
+ const [ rows , fields ] = await this . pool . promise ( )
59
+ . execute < RowDataPacket [ ] > ( "SELECT COUNT(1) AS cnt FROM channels WHERE name = ?" , [ name ] ) ;
60
+
61
+ return rows . length && rows [ 0 ] [ "cnt" ] == 0 ;
62
+ }
63
+
64
+ async createChannel ( name : string ) : Promise < boolean > {
65
+
66
+ if ( ! await this . checkIfChannelNameAvailable ( name ) ) {
67
+ throw "Channel with name '" + name + "' is not available" ;
68
+ }
69
+
70
+ const sk = Util . generateStreamKey ( ) ;
71
+
72
+ const result = await this . pool . promise ( )
73
+ . execute < ResultSetHeader > ( "INSERT INTO channels (created_at, name, stream_key) VALUES (UTC_TIMESTAMP(), ?, ?)" , [
74
+ name , sk
75
+ ] ) ;
76
+
77
+ return true ;
78
+ }
79
+
80
+ async createNewStream ( name : string , ipAddress : string , streamInfo : string ) : Promise < void > {
81
+ await this . pool . promise ( ) . execute ( "INSERT INTO streams (name, user_ip, started_at, ffprobe_json) VALUES (?, ?, UTC_TIMESTAMP(), ?)" , [
82
+ name , ipAddress , streamInfo
83
+ ] ) ;
84
+ }
85
+
86
+ async updateStreamInfo ( name : string , bytesIn : number ) : Promise < void > {
87
+
88
+ await this . pool . promise ( ) . execute ( "UPDATE streams SET ended_at = UTC_TIMESTAMP(), bytes_in = ? WHERE name = ?" , [
89
+ bytesIn ,
90
+ name
91
+ ] ) ;
92
+ }
93
+ }
0 commit comments