Skip to content

Commit

Permalink
added PowerManager service
Browse files Browse the repository at this point in the history
  • Loading branch information
itsManjeet committed Aug 22, 2024
1 parent fda0406 commit 9cb104f
Show file tree
Hide file tree
Showing 14 changed files with 382 additions and 22 deletions.
46 changes: 42 additions & 4 deletions cmd/capsule/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,63 @@ import (
"fmt"
"log"
"os"
"path"
"rlxos/pkg/capsule"
"strings"

"github.com/lmorg/readline"
)

var (
rcFiles = []string{
"/etc/rc.cap",
path.Join(os.Getenv("HOME"), ".rc.cap"),
}

defaultPrompt = ">> "
historyFile = path.Join(os.Getenv("HOME"), ".history")
)

func main() {
interactive := false
var source string
if len(os.Args) == 1 {
interactive = true
}

rl := readline.NewInstance()

scope := capsule.NewGlobalScope()
addUnixCommands(scope)
useRc(scope, rcFiles...)

if !interactive {
filename := os.Args[1]
data, err := os.ReadFile(filename)
if err != nil {
log.Fatal("failed to read", filename)
}
source = string(data)

source = strings.TrimSpace(string(data))
if strings.HasPrefix(source, "#!") {
if idx := strings.Index(source, "\n"); idx != -1 {
source = source[idx+1:]
}
}
} else {
if data, err := os.ReadFile(historyFile); err == nil {
for _, line := range strings.Split(string(data), "\n") {
rl.History.Write(line)
}
}
}
rl := readline.NewInstance()

for {
if interactive {
rl.SetPrompt("> ")
if value, err := scope.Get(capsule.Symbol{Val: "*PROMPT*"}); err == nil {
defaultPrompt = value.(string)
}

rl.SetPrompt(defaultPrompt)
for !isComplete(source) {
line, err := rl.Readline()
if err != nil {
Expand Down Expand Up @@ -87,3 +114,14 @@ func isComplete(source string) bool {
}
return len(stack) == 0
}

func useRc(scope capsule.IScope, rcfiles ...string) {
for _, rc := range rcfiles {
if _, err := os.Stat(rc); err == nil {
if _, err := capsule.Run(rc, scope); err != nil {
fmt.Printf("failed to read rc file %s: %v\n", rc, err)
continue
}
}
}
}
21 changes: 21 additions & 0 deletions cmd/poweroff/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"log"
"rlxos/services"
"rlxos/services/power/service"
)

func main() {
client, err := services.Import(service.PowerManager{})
if err != nil {
log.Fatal(err)
}

args := service.RebootArgs{}
var reply service.PoweroffReply

if err := client.Call("Poweroff", args, &reply); err != nil {
log.Fatal(err)
}
}
11 changes: 9 additions & 2 deletions external.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ RLXOS_LICENSE_FILES = LICENSE
RLXOS_DEPENDENCIES = host-go
RLXOS_GOMOD = rlxos

RLXOS_COMMANDS := cmd poweroff
RLXOS_COMMANDS_TARGETS := $(addprefix cmd/,$(RLXOS_COMMANDS))

RLXOS_SERVICES := power
RLXOS_SERVICES_TARGETS := $(addprefix services/,$(RLXOS_SERVICES))

RLXOS_BUILD_TARGETS = \
cmd/capsule
$(RLXOS_COMMANDS_TARGETS) \
$(RLXOS_SERVICES_TARGETS)

RLXOS_INSTALL_BINS = $(notdir $(RLXOS_BUILD_TARGETS))

Expand All @@ -15,7 +22,7 @@ rlxos: host-go
$(HOST_GO_HOST_ENV) \
$(RLXOS_GO_ENV) \
$(GO_BIN) build -v $(RLXOS_BUILD_OPTS) \
-mod=vendor -o $(TARGET_DIR)/bin/$(or $(RLXOS_BIN_NAME),$(notdir $(d))) \
-mod=vendor -o $(TARGET_DIR)/$(shell dirname $(d))/$(or $(RLXOS_BIN_NAME),$(notdir $(d))) \
$(RLXOS_GOMOD)/$(d))

PACKAGES_ALL += rlxos
Expand Down
11 changes: 5 additions & 6 deletions pkg/capsule/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,8 @@ var NS = map[string]Capsule{
"atom": call1e(func(a []Capsule) (Capsule, error) { return &Atom{a[0], nil}, nil }),
"atom?": call1b(AtomQ),
"deref": call1e(deref),
"reset!": call2e(reset_BANG),
"swap!": callNe(swap_BANG),
"reset": call2e(reset_BANG),
"swap": callNe(swap_BANG),
}

// callXX functions check the number of arguments
Expand Down Expand Up @@ -564,8 +564,7 @@ func defineBuiltins(scope IScope) {
}, nil})
scope.Set(Symbol{"*ARGV*"}, List{})

Eval("(def! *host-language* \"go\")", scope)
Eval("(def! not (fn* (a) (if a false true)))", scope)
Eval("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", scope)
Eval("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", scope)
Eval("(define (not a) (if a false true))", scope)
Eval("(define (load-file f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\"))))", scope)
Eval("(defmacro cond (lambda (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", scope)
}
44 changes: 34 additions & 10 deletions pkg/capsule/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package capsule

import (
"errors"
"fmt"
"os"
)

func startsWith(xs []Capsule, sym string) bool {
Expand Down Expand Up @@ -166,13 +168,26 @@ func EvalCapsule(ast Capsule, env IScope) (Capsule, error) {
a0sym = a0.(Symbol).Val
}
switch a0sym {
case "def!":
res, e := EvalCapsule(a2, env)
if e != nil {
return nil, e
case "define":
var symbol Symbol
var value Capsule
if seq, e := GetSlice(a1); e == nil {
if len(seq) == 0 {
return nil, fmt.Errorf("'define' function expect function name")
}
symbol = seq[0].(Symbol)
value = Lambda{EvalCapsule, a2, env, List{Val: seq[1:]}, false, NewScope, nil}
} else {
var e error
value, e = EvalCapsule(a2, env)
if e != nil {
return nil, e
}
symbol = a1.(Symbol)
}
return env.Set(a1.(Symbol), res), nil
case "let*":

return env.Set(symbol, value), nil
case "let":
let_env, e := NewScope(env, nil, nil)
if e != nil {
return nil, e
Expand All @@ -199,7 +214,7 @@ func EvalCapsule(ast Capsule, env IScope) (Capsule, error) {
return quasiQuote(a1), nil
case "quasiquote":
ast = quasiQuote(a1)
case "defmacro!":
case "defmacro":
fn, e := EvalCapsule(a2, env)
fn = fn.(Lambda).SetMacro()
if e != nil {
Expand All @@ -208,15 +223,15 @@ func EvalCapsule(ast Capsule, env IScope) (Capsule, error) {
return env.Set(a1.(Symbol), fn), nil
case "macroexpand":
return macroExpand(a1, env)
case "try*":
case "try":
var exc Capsule
exp, e := EvalCapsule(a1, env)
if e == nil {
return exp, nil
} else {
if a2 != nil && ListQ(a2) {
a2s, _ := GetSlice(a2)
if SymbolQ(a2s[0]) && (a2s[0].(Symbol).Val == "catch*") {
if SymbolQ(a2s[0]) && (a2s[0].(Symbol).Val == "catch") {
switch e := e.(type) {
case CapsuleError:
exc = e.Obj
Expand Down Expand Up @@ -260,7 +275,7 @@ func EvalCapsule(ast Capsule, env IScope) (Capsule, error) {
} else {
ast = a2
}
case "fn*":
case "lambda":
fn := Lambda{EvalCapsule, a2, env, a1, false, NewScope, nil}
return fn, nil
default:
Expand Down Expand Up @@ -298,3 +313,12 @@ func Eval(str string, scope IScope) (cap Capsule, err error) {
}
return
}

func Run(filepath string, scope IScope) (cap Capsule, err error) {
data, err := os.ReadFile(filepath)
if err != nil {
return nil, err
}

return Eval(string(data), scope)
}
20 changes: 20 additions & 0 deletions services/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package services

import (
"fmt"
"path"
"reflect"
)

func getObjectId(object interface{}) string {
t := reflect.TypeOf(object)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
id := t.Name()
return id
}

func getObjectSocket(object interface{}) string {
return path.Join(servicesPath, fmt.Sprintf("%s.sock", getObjectId(object)))
}
51 changes: 51 additions & 0 deletions services/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package services

import (
"fmt"
"log"
"net"
"net/rpc"
"os"
)

const (
servicesPath = "/run/services"
)

type Middleware func(id string, conn net.Conn) error

func Export(object interface{}, middlewares ...Middleware) error {
id := getObjectId(object)
socketPath := getObjectSocket(object)
if _, err := os.Stat(socketPath); err == nil {
return fmt.Errorf("service socket already exists")
}

loadPolicies()

rpc.Register(object)
listener, err := net.Listen("unix", socketPath)
if err != nil {
return err
}
defer listener.Close()
defer os.Remove(socketPath)

for {
conn, err := listener.Accept()
if err != nil {
log.Printf("ERROR: [%s] failed to accept connection %v", id, err)
continue
}

for _, middleware := range append([]Middleware{AuthenticationMiddleware}, middlewares...) {
if err := middleware(id, conn); err != nil {
conn.Close()
return err
}
}

go rpc.ServeConn(conn)
}

}
38 changes: 38 additions & 0 deletions services/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package services

import (
"fmt"
"net"
"net/rpc"
"os"
)

type Client struct {
conn net.Conn
client *rpc.Client
id string
}

func (c *Client) Call(fun string, args any, reply any) error {
return c.client.Call(fmt.Sprintf("%s.%s", c.id, fun), args, reply)
}

func Import(object interface{}) (*Client, error) {
id := getObjectId(object)
socketPath := getObjectSocket(object)

if _, err := os.Stat(socketPath); err != nil {
return nil, fmt.Errorf("service socket not exists")
}

conn, err := net.Dial("unix", socketPath)
if err != nil {
return nil, fmt.Errorf("failed to connect to server: %v", err)
}

return &Client{
id: id,
conn: conn,
client: rpc.NewClient(conn),
}, nil
}
Loading

0 comments on commit 9cb104f

Please sign in to comment.