<commit_before>package api

import (
	"emp/db"
	"emp/objects"
	"fmt"
	"quibit"
	"time"
)

// Handle a Version Request or Reply
func fVERSION(config *ApiConfig, frame quibit.Frame, version *objects.Version) {

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a version message as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	// Verify Protcol Version, else Disconnect
	if version.Version != objects.LOCAL_VERSION {
		config.Log <- fmt.Sprintf("Peer protocol version does not match local version: %d", version.Version)
		quibit.KillPeer(frame.Peer)
		return
	}

	// Verify Timestamp (5 minute window), else Disconnect
	dur := time.Since(version.Timestamp)
	if dur.Minutes()+5 > 10 {
		config.Log <- fmt.Sprintf("Peer timestamp too far off local time: %s", dur.String())
		quibit.KillPeer(frame.Peer)
		return
	}

	// If backbone node, verify IP
	backbone := false
	for _, b := range []byte(version.IpAddress) {
		if b != 0 {
			backbone = true
		}
	}

	if backbone {
		testIP := quibit.GetPeer(frame.Peer).IP
		if version.IpAddress.String() != testIP.String() {
			config.Log <- fmt.Sprintf("Backbone node broadcast incorrect IP: %s", version.IpAddress.String())
			quibit.KillPeer(frame.Peer)
			return
		}

		// Add to Master Node List
		var node objects.Node

		node.IP = version.IpAddress
		node.Port = version.Port
		node.LastSeen = time.Now().Round(time.Second)
		config.NodeList.Nodes[node.String()] = node
	}

	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send local version as a objects.REPLY
		config.LocalVersion.Timestamp = time.Now().Round(time.Second)
		sending = objects.MakeFrame(objects.VERSION, objects.REPLY, &config.LocalVersion)
	} else {
		// If a objects.REPLY, send a peer list as a objects.REQUEST
		sending = objects.MakeFrame(objects.PEER, objects.REQUEST, &config.NodeList)
	}
	sending.Peer = frame.Peer
	config.SendQueue <- *sending
} // End fVERSION

// Handle Peer List Requests or Replies
func fPEER(config *ApiConfig, frame quibit.Frame, nodeList *objects.NodeList) {

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a peer frame as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send back peer objects.REPLY
		sending = objects.MakeFrame(objects.PEER, objects.REPLY, &config.NodeList)
	} else {
		// If a objects.REPLY, send an object list as a objects.REQUEST
		sending = objects.MakeFrame(objects.OBJ, objects.REQUEST, db.ObjList())
	}

	sending.Peer = frame.Peer

	config.SendQueue <- *sending

	if nodeList != nil {

		// Merge incoming list with current list
		for key, node := range nodeList.Nodes {
			if node.IP.String() == config.LocalVersion.IpAddress.String() {
				continue
			}
			_, ok := config.NodeList.Nodes[key]
			if !ok {
				config.NodeList.Nodes[key] = node
				p := new(quibit.Peer)
				p.IP = node.IP
				p.Port = node.Port
				config.PeerQueue <- *p
				time.Sleep(time.Millisecond)
				newVer := objects.MakeFrame(objects.VERSION, objects.REQUEST, &config.LocalVersion)
				config.SendQueue <- *newVer
			} // End if
		} // End for

	}
} // End fPEER

// Handle Object Vector Requests or Replies
func fOBJ(config *ApiConfig, frame quibit.Frame, obj *objects.Obj) {
	var sending *quibit.Frame

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent an obj frame as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send local object list as objects.REPLY
		sending = objects.MakeFrame(objects.OBJ, objects.REPLY, db.ObjList())
		sending.Peer = frame.Peer
		config.SendQueue <- *sending
	}

	// For each object in object list:
	// If object not stored locally, send GETOBJ objects.REQUEST
	for _, hash := range obj.HashList {
		if db.Contains(hash) == db.NOTFOUND {
			sending = objects.MakeFrame(objects.GETOBJ, objects.REQUEST, &hash)
			sending.Peer = frame.Peer
			config.SendQueue <- *sending
		}
	}
}

// Handle Object Detail Requests
func fGETOBJ(config *ApiConfig, frame quibit.Frame, hash *objects.Hash) {
	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a getobj message as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	// If object stored locally, send object as a objects.REPLY
	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		switch db.Contains(*hash) {
		case db.PUBKEY:
			sending = objects.MakeFrame(objects.PUBKEY, objects.REPLY, db.GetPubkey(config.Log, *hash))
		case db.PURGE:
			sending = objects.MakeFrame(objects.PURGE, objects.REPLY, db.GetPurge(config.Log, *hash))
		case db.MSG:
			sending = objects.MakeFrame(objects.MSG, objects.REPLY, db.GetMessage(config.Log, *hash))
		case db.PUBKEYRQ:
			sending = objects.MakeFrame(objects.PUBKEY_REQUEST, objects.REPLY, hash)
		default:
			sending = objects.MakeFrame(objects.GETOBJ, objects.REPLY, new(objects.NilPayload))
		} // End switch
		sending.Peer = frame.Peer
		config.SendQueue <- *sending
	} // End if
} // End fGETOBJ

// Handle Public Key Request Broadcasts
func fPUBKEY_REQUEST(config *ApiConfig, frame quibit.Frame, pubHash *objects.Hash) {
	// Check Hash in Object List

	switch db.Contains(*pubHash) {
	// If request is Not in List, store the request
	case db.NOTFOUND:
		// If a objects.BROADCAST, send out another objects.BROADCAST
		db.Add(*pubHash, db.PUBKEYRQ)
		if frame.Header.Type == objects.BROADCAST {
			config.SendQueue <- *objects.MakeFrame(objects.PUBKEY_REQUEST, objects.BROADCAST, pubHash)
		}

	// If request is a Public Key in List:
	case db.PUBKEY:
		// Send out the PUBKEY as a objects.BROADCAST
		config.SendQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, db.GetPubkey(config.Log, *pubHash))
	}
}

// Handle Public Key Broadcasts
func fPUBKEY(config *ApiConfig, frame quibit.Frame, pubkey *objects.EncryptedPubkey) {
	// Check Hash in Object List
	switch db.Contains(pubkey.AddrHash) {
	// If request is a Pubkey Request, remove the pubkey request
	case db.PUBKEYRQ:
		db.Delete(pubkey.AddrHash)
		fallthrough
	case db.NOTFOUND:
		// Add Pubkey to database
		err := db.AddPubkey(config.Log, *pubkey)
		if err != nil {
			config.Log <- fmt.Sprintf("Error adding pubkey to database: %s", err)
			break
		}
		// If a objects.BROADCAST, send a objects.BROADCAST
		if frame.Header.Type == objects.BROADCAST {
			config.SendQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, pubkey)
		}

		config.PubkeyRegister <- pubkey.AddrHash
	}
} // End fPUBKEY

// Handle Encrypted Message Broadcasts
func fMSG(config *ApiConfig, frame quibit.Frame, msg *objects.Message) {
	// Check Hash in Object List
	switch db.Contains(msg.TxidHash) {
	// If Not in List, Store and objects.BROADCAST
	case db.NOTFOUND:
		err := db.AddMessage(config.Log, msg)
		if err != nil {
			config.Log <- fmt.Sprintf("Error adding message to database: %s", err)
			break
		}
		if frame.Header.Type == objects.BROADCAST {
			config.Log <- "Rebroadcasting encrypted message..."
			config.SendQueue <- *objects.MakeFrame(objects.MSG, objects.BROADCAST, msg)<commit_msg>More debugging<commit_after>package api

import (
	"emp/db"
	"emp/objects"
	"fmt"
	"quibit"
	"time"
)

// Handle a Version Request or Reply
func fVERSION(config *ApiConfig, frame quibit.Frame, version *objects.Version) {

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a version message as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	// Verify Protcol Version, else Disconnect
	if version.Version != objects.LOCAL_VERSION {
		config.Log <- fmt.Sprintf("Peer protocol version does not match local version: %d", version.Version)
		quibit.KillPeer(frame.Peer)
		return
	}

	// Verify Timestamp (5 minute window), else Disconnect
	dur := time.Since(version.Timestamp)
	if dur.Minutes()+5 > 10 {
		config.Log <- fmt.Sprintf("Peer timestamp too far off local time: %s", dur.String())
		quibit.KillPeer(frame.Peer)
		return
	}

	// If backbone node, verify IP
	backbone := false
	for _, b := range []byte(version.IpAddress) {
		if b != 0 {
			backbone = true
		}
	}

	if backbone {
		testIP := quibit.GetPeer(frame.Peer).IP
		if version.IpAddress.String() != testIP.String() {
			config.Log <- fmt.Sprintf("Backbone node broadcast incorrect IP: %s", version.IpAddress.String())
			quibit.KillPeer(frame.Peer)
			return
		}

		// Add to Master Node List
		var node objects.Node

		node.IP = version.IpAddress
		node.Port = version.Port
		node.LastSeen = time.Now().Round(time.Second)
		config.NodeList.Nodes[node.String()] = node
	}

	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send local version as a objects.REPLY
		config.LocalVersion.Timestamp = time.Now().Round(time.Second)
		sending = objects.MakeFrame(objects.VERSION, objects.REPLY, &config.LocalVersion)
	} else {
		// If a objects.REPLY, send a peer list as a objects.REQUEST
		sending = objects.MakeFrame(objects.PEER, objects.REQUEST, &config.NodeList)
	}
	sending.Peer = frame.Peer
	config.SendQueue <- *sending
} // End fVERSION

// Handle Peer List Requests or Replies
func fPEER(config *ApiConfig, frame quibit.Frame, nodeList *objects.NodeList) {

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a peer frame as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send back peer objects.REPLY
		sending = objects.MakeFrame(objects.PEER, objects.REPLY, &config.NodeList)
	} else {
		// If a objects.REPLY, send an object list as a objects.REQUEST
		sending = objects.MakeFrame(objects.OBJ, objects.REQUEST, db.ObjList())
	}

	sending.Peer = frame.Peer

	config.SendQueue <- *sending

	if nodeList != nil {

		// Merge incoming list with current list
		for key, node := range nodeList.Nodes {
			if node.IP.String() == config.LocalVersion.IpAddress.String() {
				continue
			}
			_, ok := config.NodeList.Nodes[key]
			if !ok {
				config.NodeList.Nodes[key] = node
				p := new(quibit.Peer)
				p.IP = node.IP
				p.Port = node.Port
				config.PeerQueue <- *p
				time.Sleep(time.Millisecond)
				newVer := objects.MakeFrame(objects.VERSION, objects.REQUEST, &config.LocalVersion)
				config.SendQueue <- *newVer
			} // End if
		} // End for

	}
} // End fPEER

// Handle Object Vector Requests or Replies
func fOBJ(config *ApiConfig, frame quibit.Frame, obj *objects.Obj) {
	var sending *quibit.Frame

	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent an obj frame as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	if frame.Header.Type == objects.REQUEST {
		// If a objects.REQUEST, send local object list as objects.REPLY
		sending = objects.MakeFrame(objects.OBJ, objects.REPLY, db.ObjList())
		sending.Peer = frame.Peer
		config.SendQueue <- *sending
	}

	// For each object in object list:
	// If object not stored locally, send GETOBJ objects.REQUEST
	for _, hash := range obj.HashList {
		if db.Contains(hash) == db.NOTFOUND {
			sending = objects.MakeFrame(objects.GETOBJ, objects.REQUEST, &hash)
			sending.Peer = frame.Peer
			config.SendQueue <- *sending
		}
	}
}

// Handle Object Detail Requests
func fGETOBJ(config *ApiConfig, frame quibit.Frame, hash *objects.Hash) {
	// Verify not objects.BROADCAST
	if frame.Header.Type == objects.BROADCAST {
		// SHUN THE NODE! SHUN IT WITH FIRE!
		config.Log <- "Node sent a getobj message as a broadcast. Disconnecting..."
		quibit.KillPeer(frame.Peer)
		return
	}

	// If object stored locally, send object as a objects.REPLY
	var sending *quibit.Frame
	if frame.Header.Type == objects.REQUEST {
		switch db.Contains(*hash) {
		case db.PUBKEY:
			sending = objects.MakeFrame(objects.PUBKEY, objects.REPLY, db.GetPubkey(config.Log, *hash))
		case db.PURGE:
			sending = objects.MakeFrame(objects.PURGE, objects.REPLY, db.GetPurge(config.Log, *hash))
		case db.MSG:
			sending = objects.MakeFrame(objects.MSG, objects.REPLY, db.GetMessage(config.Log, *hash))
		case db.PUBKEYRQ:
			sending = objects.MakeFrame(objects.PUBKEY_REQUEST, objects.REPLY, hash)
		default:
			sending = objects.MakeFrame(objects.GETOBJ, objects.REPLY, new(objects.NilPayload))
		} // End switch
		sending.Peer = frame.Peer
		config.SendQueue <- *sending
	} // End if
} // End fGETOBJ

// Handle Public Key Request Broadcasts
func fPUBKEY_REQUEST(config *ApiConfig, frame quibit.Frame, pubHash *objects.Hash) {
	// Check Hash in Object List

	switch db.Contains(*pubHash) {
	// If request is Not in List, store the request
	case db.NOTFOUND:
		// If a objects.BROADCAST, send out another objects.BROADCAST
		db.Add(*pubHash, db.PUBKEYRQ)
		if frame.Header.Type == objects.BROADCAST {
			config.SendQueue <- *objects.MakeFrame(objects.PUBKEY_REQUEST, objects.BROADCAST, pubHash)
		}

	// If request is a Public Key in List:
	case db.PUBKEY:
		// Send out the PUBKEY as a objects.BROADCAST
		config.SendQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, db.GetPubkey(config.Log, *pubHash))
	}
}

// Handle Public Key Broadcasts
func fPUBKEY(config *ApiConfig, frame quibit.Frame, pubkey *objects.EncryptedPubkey) {
	// Check Hash in Object List
	switch db.Contains(pubkey.AddrHash) {
	// If request is a Pubkey Request, remove the pubkey request
	case db.PUBKEYRQ:
		db.Delete(pubkey.AddrHash)
		fallthrough
	case db.NOTFOUND:
		// Add Pubkey to database
		err := db.AddPubkey(config.Log, *pubkey)
		if err != nil {
			config.Log <- fmt.Sprintf("Error adding pubkey to database: %s", err)
			break
		}
		// If a objects.BROADCAST, send a objects.BROADCAST
		if frame.Header.Type == objects.BROADCAST {
			config.SendQueue <- *objects.MakeFrame(objects.PUBKEY, objects.BROADCAST, pubkey)
		} else {
			fmt.Println("Frame Header Type: ", frame.Header.Type)
		}

		config.PubkeyRegister <- pubkey.AddrHash
	}
} // End fPUBKEY

// Handle Encrypted Message Broadcasts
func fMSG(config *ApiConfig, frame quibit.Frame, msg *objects.Message) {
	// Check Hash in Object List
	switch db.Contains(msg.TxidHash) {
	// If Not in List, Store and objects.BROADCAST
	case db.NOTFOUND:
		err := db.AddMessage(config.Log, msg)
		if err != nil {
			config.Log <- fmt.Sprintf("Error adding message to database: %s", err)
			break
		}
		if frame.Header.Type == objects.BROADCAST {
			config.Log <- "Rebroadcasting encrypted message..."
			config.SendQueue <- *objects.MakeFrame(objects.MSG, objects.BROADCAST, msg)
{'fraction_non_alphanumeric': 0.12134609039920818, 'fraction_numerical': 0.0006598482349059716, 'mean_word_length': 3.55956678700361, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4581915', 'n_tokens_mistral': 5567, 'n_tokens_neox': 5139, 'n_words': 1359}