generated from taciturnaxolotl/kreva-template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
176 lines (147 loc) · 4.81 KB
/
main.go
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"io"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/charmbracelet/log"
"github.com/charmbracelet/ssh"
"github.com/charmbracelet/wish"
"github.com/charmbracelet/wish/logging"
"github.com/go-pg/pg/v10"
"github.com/joho/godotenv"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
shorturl "github.com/aviddiviner/shortcode-go"
humanize "github.com/dustin/go-humanize"
database "github.com/kcoderhtml/pip/db"
"github.com/kcoderhtml/pip/httpServer"
"github.com/kcoderhtml/pip/styles"
"github.com/kcoderhtml/pip/utils"
)
const (
host = "localhost"
port = "23234"
)
func main() {
err := godotenv.Load() // 👈 load .env file
if err != nil {
log.Fatal(err)
}
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
// Connect to a database
dsn := os.Getenv("DATABASE_URL")
opt, err := pg.ParseURL(dsn)
if err != nil {
log.Error("Could not parse DSN", "error", err)
return
}
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
db := bun.NewDB(sqldb, pgdialect.New())
// ping db
err = db.Ping()
if err != nil {
log.Error("Could not connect to the database", "error", err)
return
}
log.Info("Connected to the database", "addr", opt.Addr, "user", opt.User, "database", opt.Database)
err = database.CreateSchema(db)
if err != nil {
log.Error("Could not create schema", "error", err)
return
}
detector, err := utils.NewLangDetector(os.Getenv("GUESSLANG_URL"))
if err != nil {
log.Error("Could not initialize language detector", "error", err)
return
}
log.Info("Initialized language detector", "url", os.Getenv("GUESSLANG_URL"))
httpServer := httpServer.NewServer("localhost:8080", db)
log.Info("Starting HTTP server", "port", 8080)
s, err := wish.NewServer(
wish.WithAddress(net.JoinHostPort(host, port)),
wish.WithHostKeyPath(".ssh/id_ed25519"),
wish.WithPublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
return true
}),
wish.WithMiddleware(
func(next ssh.Handler) ssh.Handler {
return func(sess ssh.Session) {
// if the current session's user public key is one of the
// known users, we greet them and return.
user, message, err := database.GetUser(db, sess)
if err != nil {
wish.Println(sess, message)
if !errors.Is(err, database.ErrUnauthorized) {
log.Error("Could not get user", "error", err)
}
next(sess)
return
}
wish.Println(sess, message)
_, _, isPty := sess.Pty()
if isPty {
wish.Println(sess, styles.Normal.Render("\nTo upload a paste simply run: "+styles.Code.Render("cat example.md | ssh dunkirk.sh")+"\n"))
next(sess)
wish.Println(sess, styles.Normal.Render("\nYou currently have "+styles.Code.Render(fmt.Sprintf("%d", len(user.Pastes)))+" pastes totaling "+humanize.Bytes(user.PastesSize)+".\n"))
return
}
// read any input
content := make([]byte, 0)
size := uint64(0)
buf := make([]byte, 512*1024) // 512kib
n, err := sess.Read(buf)
isEOF := errors.Is(err, io.EOF)
if err != nil && !isEOF {
log.Error("Could not read from session", "error", err)
return
}
size += uint64(n)
content = append(content, buf[:n]...)
fmt.Println("size", size, "n", n, "isEOF", isEOF, "err", err, "content", string(content))
answer, err := detector.GetLang(string(buf))
if err != nil {
log.Error("Could not guess language", "error", err)
}
wish.Println(sess, styles.Normal.Render("\nDetected language: "+styles.Info.Render(answer)+"\nSize: "+styles.Info.Render(humanize.Bytes(size))+"\n"))
res, err := database.CreatePaste(db, user, string(content), answer, "never", size)
if err != nil {
log.Error("Could not create paste", "error", err)
}
wish.Println(sess, styles.Info.Render("Paste Saved!"+"\n"+styles.Normal.Render("To view your paste visit: ")+styles.Code.Render("https://pip.dunkirk.sh/"+shorturl.EncodeID(int(res.ID)))))
next(sess)
}
},
logging.Middleware(),
),
)
if err != nil {
log.Error("Could not start server", "error", err)
}
log.Info("Starting SSH server", "host", host, "port", port)
go func() {
if err = s.ListenAndServe(); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not start server", "error", err)
done <- nil
}
}()
log.Info("Ready!")
<-done
log.Info("Stopping servers")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer func() { cancel() }()
if err := s.Shutdown(ctx); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not stop SSH server", "error", err)
}
if err := httpServer.Shutdown(ctx); err != nil {
log.Error("Could not stop HTTP server", "error", err)
}
}