aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/.gitignore200
-rwxr-xr-xserver/bun.lockbbin79826 -> 0 bytes
-rw-r--r--server/controllers/bin.js100
-rw-r--r--server/controllers/health.js7
-rw-r--r--server/go.mod10
-rw-r--r--server/go.sum8
-rw-r--r--server/index.js18
-rw-r--r--server/main.go142
-rw-r--r--server/package.json23
-rw-r--r--server/routes/bin.js11
-rw-r--r--server/routes/health.js8
-rw-r--r--server/tsconfig.json22
12 files changed, 185 insertions, 364 deletions
diff --git a/server/.gitignore b/server/.gitignore
index ce007ac..c2cb318 100644
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -1,175 +1,25 @@
-# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
-
-# Logs
-
-logs
-_.log
-npm-debug.log_
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-.pnpm-debug.log*
-
-# Caches
-
-.cache
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-
-report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
-
-# Runtime data
-
-pids
-_.pid
-_.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-
-lib-cov
-
-# Coverage directory used by tools like istanbul
-
-coverage
-*.lcov
-
-# nyc test coverage
-
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-
-bower_components
-
-# node-waf configuration
-
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-
-build/Release
-
-# Dependency directories
-
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-
-web_modules/
-
-# TypeScript cache
-
-*.tsbuildinfo
-
-# Optional npm cache directory
-
-.npm
-
-# Optional eslint cache
-
-.eslintcache
-
-# Optional stylelint cache
-
-.stylelintcache
-
-# Microbundle cache
-
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-
-.node_repl_history
-
-# Output of 'npm pack'
-
-*.tgz
-
-# Yarn Integrity file
-
-.yarn-integrity
-
-# dotenv environment variable files
-
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# parcel-bundler cache (https://parceljs.org/)
-
-.parcel-cache
-
-# Next.js build output
-
-.next
-out
-
-# Nuxt.js build / generate output
-
-.nuxt
-dist
-
-# Gatsby files
-
-# Comment in the public line in if your project uses Gatsby and not Next.js
-
-# https://nextjs.org/blog/next-9-1#public-directory-support
-
-# public
-
-# vuepress build output
-
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-
-.temp
-
-# Docusaurus cache and generated files
-
-.docusaurus
-
-# Serverless directories
-
-.serverless/
-
-# FuseBox cache
-
-.fusebox/
-
-# DynamoDB Local files
-
-.dynamodb/
-
-# TernJS port file
-
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-
-.vscode-test
-
-# yarn v2
-
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
-
-# IntelliJ based IDEs
-.idea
-
-# Finder (MacOS) folder config
-.DS_Store \ No newline at end of file
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+minibin
+
+# Database
+*.db
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
diff --git a/server/bun.lockb b/server/bun.lockb
deleted file mode 100755
index 0ba4f0e..0000000
--- a/server/bun.lockb
+++ /dev/null
Binary files differ
diff --git a/server/controllers/bin.js b/server/controllers/bin.js
deleted file mode 100644
index 882ecef..0000000
--- a/server/controllers/bin.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import sqlite3 from "sqlite3";
-
-const dbPath = "./database/bins.db";
-
-function createBinTable() {
- const db = new sqlite3.Database(dbPath, (err) => {
- if (err) {
- console.error("Error connecting to database:", err.message);
- return;
- }
-
- const sql = `CREATE TABLE IF NOT EXISTS bin (
- id TEXT PRIMARY KEY,
- html_content TEXT
- )`;
-
- db.run(sql, (err) => {
- if (err) {
- console.error("Error creating table:", err.message);
- } else {
- console.log("`bin` table created successfully");
- }
-
- db.close((err) => {
- if (err) {
- console.error("Error closing database:", err.message);
- }
- });
- });
- });
-}
-
-const createBin = (req, res) => {
- console.log(`createBin: ${req.body}`);
- const { html_content } = req.body;
- const id = Math.random().toString(36).substring(7);
-
- const db = new sqlite3.Database(dbPath, (err) => {
- if (err) {
- console.error("Error connecting to database:", err.message);
- throw err; // Re-throw for async handling
- }
-
- const sql = `INSERT INTO bin (id, html_content) VALUES (?, ?)`;
-
- db.run(sql, [id, html_content], (err) => {
- if (err) {
- console.error("Error creating entry:", err.message);
- throw err; // Re-throw for async handling
- } else {
- res.status(201).json({ id });
- console.log("Entry created successfully:", id);
- }
-
- db.close((err) => {
- if (err) {
- console.error("Error closing database:", err.message);
- }
- });
- });
- });
-};
-
-const getBin = async (req, res) => {
- const { id } = req.params;
- if (!id) {
- throw new Error("Missing required parameter: id"); // Throw error for missing ID
- }
-
- const db = new sqlite3.Database(dbPath, (err) => {
- if (err) {
- console.error("Error connecting to database:", err.message);
- throw err; // Re-throw for async handling
- }
-
- const sql = `SELECT * FROM bin WHERE id = ?`;
-
- db.get(sql, [id], (err, row) => {
- if (err) {
- console.error("Error retrieving entry:", err.message);
- throw err; // Re-throw for async handling
- } else if (!row) {
- console.log("Entry not found:", id);
- return null; // Handle case where no entry exists
- }
-
- res.status(200).json(row);
- console.log("Entry retrieved:", id);
- db.close((err) => {
- if (err) {
- console.error("Error closing database:", err.message);
- }
- });
-
- return row;
- });
- });
-};
-
-export default { createBinTable, createBin, getBin };
diff --git a/server/controllers/health.js b/server/controllers/health.js
deleted file mode 100644
index d31c489..0000000
--- a/server/controllers/health.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const healthCheck = async (req, res) => {
- return res.json({
- uptime: process.uptime(),
- });
-};
-
-export default { healthCheck };
diff --git a/server/go.mod b/server/go.mod
new file mode 100644
index 0000000..c15dae4
--- /dev/null
+++ b/server/go.mod
@@ -0,0 +1,10 @@
+module minibin
+
+go 1.22.0
+
+require (
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/mux v1.8.1 // indirect
+ github.com/mattn/go-sqlite3 v1.14.22 // indirect
+ github.com/rs/cors v1.10.1 // indirect
+)
diff --git a/server/go.sum b/server/go.sum
new file mode 100644
index 0000000..a0572d7
--- /dev/null
+++ b/server/go.sum
@@ -0,0 +1,8 @@
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
+github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
diff --git a/server/index.js b/server/index.js
deleted file mode 100644
index 57546fd..0000000
--- a/server/index.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import Express from "express";
-import cors from "cors";
-import dotenv from "dotenv";
-
-import binRoutes from "./routes/bin.js";
-import healthRoutes from "./routes/health.js";
-
-const app = Express();
-dotenv.config();
-
-app.use(cors());
-app.use(Express.json());
-app.use("/", healthRoutes);
-app.use("/bin", binRoutes);
-
-const PORT = process.env.PORT;
-
-app.listen(PORT, () => console.log(`Server running on PORT: ${PORT}`));
diff --git a/server/main.go b/server/main.go
new file mode 100644
index 0000000..4618e5b
--- /dev/null
+++ b/server/main.go
@@ -0,0 +1,142 @@
+package main
+
+import (
+ "database/sql"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "net/http"
+ "strings"
+ "time"
+
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/rs/cors"
+)
+
+var db *sql.DB
+var port int
+var dbFilePath string
+
+type Bin struct {
+ Content string `json:"content"`
+ Language string `json:"language"`
+}
+
+const (
+ shortIDCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ shortIDLength = 8
+)
+
+func main() {
+ flag.IntVar(&port, "port", 8080, "Port number for the server (default is 8080)")
+ flag.StringVar(&dbFilePath, "db", "./minibin.db", "Database file path")
+ flag.Parse()
+
+ setupServer()
+}
+
+func setupServer() {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/bin", postBin)
+ mux.HandleFunc("/bin/", getBin)
+ handler := cors.Default().Handler(mux)
+ serverAddr := fmt.Sprintf(":%d", port)
+ log.Printf("Server listening on port %d...\n", port)
+ initDatabase()
+ log.Fatal(http.ListenAndServe(serverAddr, handler))
+}
+
+func initDatabase() {
+ var err error
+ db, err = sql.Open("sqlite3", dbFilePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = createTable()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func postBin(w http.ResponseWriter, r *http.Request) {
+ handleRequestMethod(w, r, "POST", func() {
+ body, err := ioutil.ReadAll(r.Body)
+ if handleError(w, err, http.StatusInternalServerError) {
+ return
+ }
+ var bin Bin
+ err = json.Unmarshal(body, &bin)
+ if handleError(w, err, http.StatusBadRequest) {
+ return
+ }
+ id := generateShortID()
+ handleError(w, saveBin(id, bin), http.StatusInternalServerError)
+ respondWithJSON(w, http.StatusOK, map[string]string{"id": id, "content": bin.Content, "language": bin.Language})
+ })
+}
+
+func getBin(w http.ResponseWriter, r *http.Request) {
+ handleRequestMethod(w, r, "GET", func() {
+ id := strings.TrimPrefix(r.URL.Path, "/bin/")
+ bin, err := getBinById(id)
+ handleError(w, err, http.StatusInternalServerError)
+ respondWithJSON(w, http.StatusOK, bin)
+ })
+}
+
+func handleRequestMethod(w http.ResponseWriter, r *http.Request, expectedMethod string, handler func()) {
+ if r.Method != expectedMethod {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+ handler()
+}
+
+func handleError(w http.ResponseWriter, err error, statusCode int) bool {
+ if err != nil {
+ http.Error(w, err.Error(), statusCode)
+ return true
+ }
+ return false
+}
+
+func respondWithJSON(w http.ResponseWriter, statusCode int, data interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(statusCode)
+ json.NewEncoder(w).Encode(data)
+}
+
+func createTable() error {
+ _, err := db.Exec(`
+ CREATE TABLE IF NOT EXISTS bins (
+ id TEXT PRIMARY KEY,
+ content TEXT,
+ language TEXT
+ )
+`)
+ return err
+}
+
+func getBinById(id string) (Bin, error) {
+ var bin Bin
+ err := db.QueryRow("SELECT content, language FROM bins WHERE id = ?", id).Scan(&bin.Content, &bin.Language)
+ return bin, err
+}
+
+func saveBin(id string, bin Bin) error {
+ _, err := db.Exec("INSERT INTO bins (id, content, language) VALUES (?, ?, ?)", id, bin.Content, bin.Language)
+ return err
+}
+
+func generateShortID() string {
+ rand.Seed(time.Now().UnixNano())
+ id := make([]byte, shortIDLength)
+ for i := range id {
+ id[i] = shortIDCharset[rand.Intn(len(shortIDCharset))]
+ }
+ return string(id)
+}
diff --git a/server/package.json b/server/package.json
deleted file mode 100644
index a74b362..0000000
--- a/server/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "minibun-server",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "type": "module",
- "scripts": {
- "start": "nodemon index.js",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "devDependencies": {
- "cors": "^2.8.5",
- "dotenv": "^16.4.4",
- "nodemon": "^3.0.3"
- },
- "dependencies": {
- "express": "^4.18.2",
- "sqlite3": "^5.1.7"
- }
-} \ No newline at end of file
diff --git a/server/routes/bin.js b/server/routes/bin.js
deleted file mode 100644
index 38b2ddc..0000000
--- a/server/routes/bin.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import Express from "express";
-import bin from "../controllers/bin.js";
-
-const router = Express.Router();
-
-bin.createBinTable();
-
-router.get("/:id", bin.getBin);
-router.post("/", bin.createBin);
-
-export default router;
diff --git a/server/routes/health.js b/server/routes/health.js
deleted file mode 100644
index 04275c9..0000000
--- a/server/routes/health.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import Express from "express";
-import health from "../controllers/health.js";
-
-const router = Express.Router();
-
-router.get("/health", health.healthCheck);
-
-export default router;
diff --git a/server/tsconfig.json b/server/tsconfig.json
deleted file mode 100644
index 761170e..0000000
--- a/server/tsconfig.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "compilerOptions": {
- "lib": ["ESNext"],
- "target": "ESNext",
- "module": "ESNext",
- "moduleDetection": "force",
- "jsx": "react-jsx",
- "allowJs": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "noEmit": true,
-
- /* Linting */
- "skipLibCheck": true,
- "strict": true,
- "noFallthroughCasesInSwitch": true,
- "forceConsistentCasingInFileNames": true
- }
- } \ No newline at end of file